我遇到了内存泄漏,我无法修复我的代码。 场景:用户打开一个新窗口,其中绘制了一个图表(在本例中为LineChart)。但是当窗口关闭时, 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();
}
}
答案 0 :(得分:1)
我能够解决问题。 致电
series.getData().clear();
关闭窗口时,每个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();
}
});
}
}
感谢@fabian指出我正确的方向。
答案 1 :(得分:0)
这很可能不是你身边的错误。我遇到了类似的问题,在运行时关闭UI的某些部分之后,一些UI数据仍留在系统内存中。
这可能不是问题的最佳解决方案,但您可以尝试重复使用Windows 您可以通过在单独的ArrayLists中跟踪所有打开的窗口和关闭的窗口来完成此操作。
如果用户想关闭窗口,则将窗口设置为不可见(而不是完全关闭)并将其移动到关闭窗口的ArrayList中。创建新窗口后,您可以检查已关闭窗口的ArrayList(如果包含窗口)。如果是这样,您可以重复使用此窗口(更改此窗口的图形并将窗口设置为可见)并将其从关闭窗口的ArrayList移动到打开窗口的ArrayList。
如果要打开一个新窗口并且打开窗口的ArrayList中没有窗口,只需创建一个窗口类的新实例并将其添加到打开窗口的ArrayList中。
这可能不是解决问题的最佳方法,但这就是我解决问题的方法,这与你的问题类似。