2016-06-17 6 views
1

メモリリークが発生しました。私のコードでは修正できません。 シナリオ:ユーザーが新しいウィンドウを開き、グラフが描画されます(この場合は線グラフ)。ウィンドウが閉じているときしかし、java.lang.ref.WeakReferencejavafx.beans.property.BooleanPropertyBase $リスナーは、メモリ内に残っています。その数は描画されたデータ点(XYChart.Data)に完全に対応しています。 私はちょうどそれらを取り除く方法を理解できません。 私のコードでは、これらのウィンドウの多くは頻繁に開かれ、閉じられ、チャートやメモリごとに10k〜100kのデータポイントがかなり速くいっぱいになります。グラフの描画時にJavaFX WeakReferenceメモリリークが発生する

私はいくつかばかな間違いをしたと確信していますが、私はそれを見つけることができません。ヘルプは非常に高く評価されるだろう!

サンプルコード:

import java.util.ArrayList; 
import java.util.List; 
import javafx.application.Application; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.XYChart; 
import javafx.scene.control.Button; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class Test extends Application { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     Application.launch(Test.class, args); 
    } 

    @Override 
    public void start(final Stage primaryStage) { 
     primaryStage.setTitle("Hello World"); 
     Group root = new Group(); 
     Scene scene = new Scene(root, 300, 250, Color.LIGHTGREEN); 
     Button btn = new Button(); 
     btn.setLayoutX(100); 
     btn.setLayoutY(80); 
     btn.setText("Create stage"); 
     btn.setOnAction(new EventHandler<ActionEvent>() { 

      public void handle(ActionEvent event) { 
       new CreateStage(); 
       primaryStage.toFront(); 

      } 
     }); 
     root.getChildren().add(btn); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 
} 

class CreateStage { 

    public CreateStage() { 
     Stage stage = new Stage(); 
      stage.setTitle("Line Chart Sample"); 
     //Basic Chart attributes 
     NumberAxis xAxis = new NumberAxis(); 
     NumberAxis yAxis = new NumberAxis(); 
     xAxis.setLabel("RT [minutes]"); 
     yAxis.setLabel("Intensity"); 
     LineChart<Number, Number> linechart = new LineChart(xAxis, yAxis); 

       XYChart.Series newSeries = new XYChart.Series(); 

       List<XYChart.Data> list = new ArrayList<>(); 
       //just fill the chart with data points 
       for (int j = 0; j < 10000; j++) { 
        float intensity = j; 
        float currentRT = j; 

        list.add(new XYChart.Data(currentRT, intensity)); 
       } 
       newSeries.getData().addAll(list); 

       // add new Series 
       linechart.getData().add(newSeries); 

     Scene scene = new Scene(linechart,800,600);  


     stage.setScene(scene); 
     stage.show(); 
    } 
} 
+0

ガベージコレクションが実際にトリガーされていますか。さらに、 'ImageView' /' Image'で同様の問題が発生しました。シーングラフから 'ImageView'を単に削除するだけで、' Image'がガベージコレクションに利用できなくなりましたが、 'ImageView'の' image'プロパティを設定したので、グラフのデータを 'null'に設定すると役立ちます。 .. – fabian

+0

はい、残念ながら、私は確信しています。私はすでに似たようなことを試みたと思いますが、私は再びそれを調べます、ありがとう! –

答えて

1

私はこの問題を解決できました。ウィンドウを閉じるのがメモリリークを取り除くとき は、すべてのXYChart.Series上

series.getData().clear(); 

を呼び出します。 javafx.scene.layout.CornerRadiicom.sun.javafx.sg.prism.NGRegionjavafx.scene.layout.Backgroundよう 物事はまだ記憶に残っているが、ごみを取得します最終的に収集され、構築されません。

ここでは固定コードです:

import java.util.ArrayList; 
import java.util.List; 
import javafx.application.Application; 
import javafx.collections.ObservableList; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.chart.LineChart; 
import javafx.scene.chart.NumberAxis; 
import javafx.scene.chart.ScatterChart; 
import javafx.scene.chart.XYChart; 
import javafx.scene.control.Button; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class Test extends Application { 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     Application.launch(Test.class, args); 
    } 

    @Override 
    public void start(final Stage primaryStage) { 
     primaryStage.setTitle("Hello World"); 
     Group root = new Group(); 
     Scene scene = new Scene(root, 300, 250, Color.LIGHTGREEN); 
     Button btn = new Button(); 
     btn.setLayoutX(100); 
     btn.setLayoutY(80); 
     btn.setText("Create stage"); 
     btn.setOnAction(new EventHandler<ActionEvent>() { 

      public void handle(ActionEvent event) { 
       CreateStage(); 
       primaryStage.toFront(); 

      } 
     }); 
     root.getChildren().add(btn); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public void CreateStage() { 

     Stage stage = new Stage(); 
     stage.setTitle("Line Chart Sample"); 
     //Basic Chart attributes 
     NumberAxis xAxis = new NumberAxis(); 
     NumberAxis yAxis = new NumberAxis(); 
     xAxis.setLabel("RT [minutes]"); 
     yAxis.setLabel("Intensity"); 

     //linechart.getData().clear(); 
     LineChart<Number, Number> linechart = new LineChart(xAxis, yAxis); 

     XYChart.Series newSeries = new XYChart.Series(); 

     List<XYChart.Data> list = new ArrayList<>(); 
     //just fill the chart with data points 
     for (int j = 0; j < 10000; j++) { 
      float intensity = j; 
      float currentRT = j; 

      list.add(new XYChart.Data(currentRT, intensity)); 
     } 
     newSeries.getData().addAll(list); 

     // add new Series 
     linechart.getData().add(newSeries); 

     Scene scene = new Scene(linechart, 800, 600); 

     stage.setScene(scene); 
     stage.show(); 

     //this fixes it 
     stage.setOnCloseRequest(event -> { 
      for (XYChart.Series series : linechart.getData()) { 
       series.getData().clear(); 
      } 

     }); 

    } 
} 

おかげで正しい方向に私を指しているため@fabianします。

0

T.K、

これが最も可能性の高いあなたの側からのミスではありません。同じような問題が発生しました。実行時にUIの一部が閉じられた後、一部のUIデータがシステムメモリに残りました。

これはおそらくこの問題の最適な解決策ではありませんが、ウィンドウを再利用することができます。
開いているすべてのウィンドウと閉じたウィンドウを別々のArrayListsで追跡することで、これを行うことができます。ユーザーがウィンドウを閉じる場合は、ウィンドウを完全に閉じずに非表示にして、閉じたウィンドウのArrayListに移動します。新しいウィンドウが作成されたら、閉じられたウィンドウのArrayListをチェックすることができます(含まれている場合)。その場合は、このウィンドウを再利用して(このウィンドウのグラフを変更してウィンドウを表示する)、閉じたウィンドウのArrayListから開いているウィンドウのArrayListに移動できます。新しいウィンドウを開き、開いているウィンドウのArrayListの中にウィンドウがない場合は、ウィンドウクラスの新しいインスタンスを作成し、それを開いたウィンドウのArrayListに追加するだけです。
これはおそらくあなたの問題のための最善の回避策ではありませんが、それはあなたのような私の問題を解決する方法です。

私はいくつかの助けとこの回避策についての私の説明が分かりやすいことを願っています。

+0

ステージを非表示にして閉じることとの違いは何ですか? (明らかにあなたの提案の主なポイントはまだ機能しています;あなたは閉じられたウィンドウのリスト/プールを維持することができますが、 "見えない"と "閉じた"の区別はありません) –

+0

良いアイデア!あなたの回避策Fabian B.のおかげで、あなたはとてもうまく説明しました!今私はこれについて何かすることができます... –

+0

@James_D "閉じた"ウィンドウは表示できなくなりました。アプリケーションによって削除されました。一方、「見えない」ウィンドウは、システムメモリにまだ表示される準備ができていますが、現時点ではユーザには表示されません。 –

関連する問題