更新JavaFX BarChart数据导致内存泄漏
Updating JavaFX BarChart data causes memory leak
我发现我认为是 JavaFX(1.8u40 GA 和 1.8u60 b10 EA)中的内存泄漏 BarChart 通过替换系列中的所有数据值触发。我们的应用程序每秒执行几次,这让我们感到恼火。
使用 jvisualvm
显示 javafx.scene.layout.StackPane 实例数量不受控制地增长,最终导致 OutOfMemoryError。条形图在内部使用样式化的 StackPane 节点。
我尝试了不同的策略来更新列表。所有人都表现出同样的问题。
// 1
series.getData().clear();
series.getData().addAll(list);
// 2
series.getData().setAll(list);
// 3
series.setData(list)
有趣的是Oracle BarChart tutorial updates values by adding all the bars/points first, and then mutating them using XYChart.Data.setYValue()中的例子。这可以工作,但对我们来说不方便,因为数据点的数量可以动态变化。
具体问题
- 除了使用上面的 setYValue() 方法的额外逻辑之外,还有什么方法可以避免这个问题。
- 我是否偶然发现了 JavaFX 中的实际内存泄漏?或者只是我滥用 API 的产物?当然,在更新数据时释放内部节点是 JavaFX 的职责
示例
public class ChartUpdate extends Application {
private int clock;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis(0, 100, 10);
yAxis.setAutoRanging(false);
BarChart<String, Number> graph = new BarChart<>(xAxis, yAxis);
graph.setAnimated(false);
Series<String, Number> series = new Series<>();
graph.getData().add(series);
stage.setScene(new Scene(graph));
stage.show();
Timeline timeLine = new Timeline();
timeLine.getKeyFrames().add(
new KeyFrame(Duration.millis(500),
(e) -> {
ObservableList<Data<String, Number>> list = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
list.add(new Data<>(String.valueOf(i), (clock + i) % 100));
}
series.setData(list);
clock++;
}));
timeLine.setCycleCount(Animation.INDEFINITE);
timeLine.play();
}
}
- 更新(2015 年 4 月 16 日)已提出 https://bugs.openjdk.java.net/browse/JDK-8094805 并发布到 OpenJFX 邮件列表
总之,这是 JavaFX 团队接受并由 JDK-8094805 在 8u60
中修复的真正问题
有关详细信息,请参阅 https://bugs.openjdk.java.net/browse/JDK-8094805。
我发现我认为是 JavaFX(1.8u40 GA 和 1.8u60 b10 EA)中的内存泄漏 BarChart 通过替换系列中的所有数据值触发。我们的应用程序每秒执行几次,这让我们感到恼火。
使用 jvisualvm
显示 javafx.scene.layout.StackPane 实例数量不受控制地增长,最终导致 OutOfMemoryError。条形图在内部使用样式化的 StackPane 节点。
我尝试了不同的策略来更新列表。所有人都表现出同样的问题。
// 1
series.getData().clear();
series.getData().addAll(list);
// 2
series.getData().setAll(list);
// 3
series.setData(list)
有趣的是Oracle BarChart tutorial updates values by adding all the bars/points first, and then mutating them using XYChart.Data.setYValue()中的例子。这可以工作,但对我们来说不方便,因为数据点的数量可以动态变化。
具体问题
- 除了使用上面的 setYValue() 方法的额外逻辑之外,还有什么方法可以避免这个问题。
- 我是否偶然发现了 JavaFX 中的实际内存泄漏?或者只是我滥用 API 的产物?当然,在更新数据时释放内部节点是 JavaFX 的职责
示例
public class ChartUpdate extends Application {
private int clock;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis(0, 100, 10);
yAxis.setAutoRanging(false);
BarChart<String, Number> graph = new BarChart<>(xAxis, yAxis);
graph.setAnimated(false);
Series<String, Number> series = new Series<>();
graph.getData().add(series);
stage.setScene(new Scene(graph));
stage.show();
Timeline timeLine = new Timeline();
timeLine.getKeyFrames().add(
new KeyFrame(Duration.millis(500),
(e) -> {
ObservableList<Data<String, Number>> list = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
list.add(new Data<>(String.valueOf(i), (clock + i) % 100));
}
series.setData(list);
clock++;
}));
timeLine.setCycleCount(Animation.INDEFINITE);
timeLine.play();
}
}
- 更新(2015 年 4 月 16 日)已提出 https://bugs.openjdk.java.net/browse/JDK-8094805 并发布到 OpenJFX 邮件列表
总之,这是 JavaFX 团队接受并由 JDK-8094805 在 8u60
中修复的真正问题有关详细信息,请参阅 https://bugs.openjdk.java.net/browse/JDK-8094805。