绘制图表时JavaFX WeakReference内存泄漏

绘制图表时JavaFX WeakReference内存泄漏,java,javafx,memory-leaks,javafx-8,Java,Javafx,Memory Leaks,Javafx 8,我遇到了一个无法在代码中修复的内存泄漏。 场景:用户打开一个新窗口,在其中绘制一个图表(在本例中为折线图)。但是当窗口关闭时,java.lang.ref.WeakReference和javafx.beans.property.BooleanPropertyBase$Listener仍保留在内存中。它们的编号与绘制的数据点(XYChart.data)完全对应。 我就是想不出如何摆脱它们。 在我的代码中,这些窗口中有许多是频繁打开和关闭的,每个图表有10k-100k个数据点,内存很快就会被填满 我肯

我遇到了一个无法在代码中修复的内存泄漏。 场景:用户打开一个新窗口,在其中绘制一个图表(在本例中为折线图)。但是当窗口关闭时,java.lang.ref.WeakReferencejavafx.beans.property.BooleanPropertyBase$Listener仍保留在内存中。它们的编号与绘制的数据点(XYChart.data)完全对应。 我就是想不出如何摆脱它们。 在我的代码中,这些窗口中有许多是频繁打开和关闭的,每个图表有10k-100k个数据点,内存很快就会被填满

我肯定我犯了一些愚蠢的错误,但我就是找不到。非常感谢您的帮助

示例代码:

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();
    }
}  
import java.util.ArrayList;
导入java.util.List;
导入javafx.application.application;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.chart.LineChart;
导入javafx.scene.chart.NumberAxis;
导入javafx.scene.chart.XYChart;
导入javafx.scene.control.Button;
导入javafx.scene.paint.Color;
导入javafx.stage.stage;
公共类测试扩展了应用程序{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
应用程序启动(Test.class,args);
}
@凌驾
公共作废开始(最终阶段初级阶段){
setTitle(“你好世界”);
组根=新组();
场景=新场景(根,300,250,颜色.浅绿色);
按钮btn=新按钮();
btn.设置布局X(100);
btn.设置布局(80);
btn.setText(“创建阶段”);
btn.setOnAction(新的EventHandler(){
公共无效句柄(ActionEvent事件){
新建CreateStage();
初级阶段toFront();
}
});
root.getChildren().add(btn);
初级阶段。场景(场景);
primaryStage.show();
}
}
类CreateStage{
公共舞台(){
阶段=新阶段();
阶段。设置标题(“折线图样本”);
//基本图表属性
NumberAxis xAxis=新NumberAxis();
NumberAxis yAxis=新的NumberAxis();
xAxis.setLabel(“RT[minutes]”;
yAxis.setLabel(“强度”);
线形图线形图=新线形图(xAxis,yAxis);
XYChart.Series newSeries=新的XYChart.Series();
列表=新的ArrayList();
//只需在图表中填入数据点即可
对于(int j=0;j<10000;j++){
漂浮强度=j;
浮动电流rt=j;
添加(新的XYChart.Data(当前RT,强度));
}
newSeries.getData().addAll(列表);
//添加新系列
linechart.getData().add(newSeries);
场景=新场景(线形图,800600);
舞台场景;
stage.show();
}
}  

这很可能不是您这边的错误。我也遇到过类似的问题,在运行时关闭UI的某些部分后,一些UI数据仍然留在系统内存中

这可能不是解决此问题的最佳解决方案,但您可以尝试重新使用windows。
您可以通过在单独的ArrayList中跟踪所有打开和关闭的窗口来实现这一点

如果用户要关闭窗口,请将窗口设置为不可见(而不是完全关闭),然后将其移动到已关闭窗口的ArrayList中。创建新窗口后,可以检查已关闭窗口的ArrayList(如果其中包含一个)。如果是这样,您可以重用此窗口(更改此窗口的图形并将窗口设置为可见),并将其从关闭窗口的ArrayList移动到打开窗口的ArrayList

如果要打开一个新窗口,而打开窗口的ArrayList中没有窗口,只需创建窗口类的新实例并将其添加到打开窗口的ArrayList中。

这可能不是解决您问题的最佳方法,但这就是我解决问题的方式,与您的问题类似

我能解决这个问题。 召唤

关闭窗口时,在每个XYChart.Series上清除内存泄漏。 像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();
            }

        });

    }
}
import java.util.ArrayList;
导入java.util.List;
导入javafx.application.application;
导入javafx.collections.ObservableList;
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.chart.LineChart;
导入javafx.scene.chart.NumberAxis;
导入javafx.scene.chart.ScatterChart;
导入javafx.scene.chart.XYChart;
导入javafx.scene.control.Button;
导入javafx.scene.paint.Color;
导入javafx.stage.stage;
公共类测试扩展了应用程序{
/**
*@param指定命令行参数
*/
公共静态void main(字符串[]args){
应用程序启动(Test.class,args);
}
@凌驾
公共作废开始(最终阶段初级阶段){
setTitle(“你好世界”);
组根=新组();
场景=新场景(根,300,250,颜色.浅绿色);
按钮btn=新按钮();
btn.设置布局X(100);
btn.设置布局(80);
btn.setText(“创建阶段”);
btn.setOnAction(新的EventHandler(){
公共无效句柄(ActionEvent事件){
CreateStage();
初级阶段toFront();
}
});
root.getChildren().add(btn);
初级阶段。场景(场景);
初级的
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();
            }

        });

    }
}