绘制图表时JavaFX WeakReference内存泄漏
我遇到了一个无法在代码中修复的内存泄漏。 场景:用户打开一个新窗口,在其中绘制一个图表(在本例中为折线图)。但是当窗口关闭时,java.lang.ref.WeakReference和javafx.beans.property.BooleanPropertyBase$Listener仍保留在内存中。它们的编号与绘制的数据点(XYChart.data)完全对应。 我就是想不出如何摆脱它们。 在我的代码中,这些窗口中有许多是频繁打开和关闭的,每个图表有10k-100k个数据点,内存很快就会被填满 我肯定我犯了一些愚蠢的错误,但我就是找不到。非常感谢您的帮助 示例代码:绘制图表时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个数据点,内存很快就会被填满 我肯
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.CornerRadii、com.sun.javafx.sg.prism.NGRegion和javafx.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();
}
});
}
}