【问题标题】:JavaFX memory leak in TableView with dynamic TableColumns具有动态 TableColumns 的 TableView 中的 JavaFX 内存泄漏
【发布时间】:2015-05-21 23:48:02
【问题描述】:

我正在使用 jdk1.8.0_40

我想制作一个可以动态更改列的 TableView,但它会在 Old/Tenured gen 中泄漏内存并最终挂起 JVM。

这是一个演示泄漏的简单程序(不包括导入):

public class Main extends Application {
    @Override
    public void start(Stage primaryStage) {    
        TableView<ObservableList<String>> tableView = new TableView<>();
        Button button = new Button("button");

        button.setOnAction((actionEvent) -> {
            // Clearing items and/or columns here doesn't remove the leak
            tableView.getItems().clear();
            tableView.getColumns().clear();

            for (int g = 0; g < 50; g++) { // iterate 50 times to see the leak quickly
                TableColumn<ObservableList<String>, String> tableColumn = new TableColumn<>("column");
                tableView.getColumns().add(tableColumn);
            }
                tableView.getItems().add(FXCollections.observableArrayList("1"));

            // clearing the items here removes the leak somehow, but also makes the table useless
            /* tableView.getItems().clear(); */
        });

        primaryStage.setScene(new Scene(new VBox(tableView, button), 800, 600));
        primaryStage.show();
    }    
    public static void main(String[] args) { launch(args); }
}

在上面的代码中,第二次按下按钮应该清除所有项目和列,确实如此,但某些引用以某种方式在某处持续存在。

我已经尝试过的一些事情:

  • 尝试搜索类似问题,但未找到任何相关内容。
  • 尝试将所有引用存储在 ArrayList 中并显式删除()而不是 clear() - 没有奏效。
  • 尝试使用 ListView,效果很好,但它不是表格,不能有列。
  • 尝试使用不同的类组合(例如,使用 StringProperty 而不是 String),这也不足为奇。

我最近才开始学习 JavaFX,所以如果是这样的话,我可能只是遗漏了一些明显的东西 - 对不起一个愚蠢的问题。

如何修复此漏洞?

如果无法修复,这是一个错误,还是这是预期的行为,我不应该动态创建 TableColumn?

【问题讨论】:

    标签: memory-leaks javafx tableview javafx-8 tablecolumn


    【解决方案1】:

    如果有人也遇到此问题,请回答我自己的问题 - 这是一个错误。

    我提交了一份 JIRA 错误报告,有关更多信息和可能的更新,请参阅 https://javafx-jira.kenai.com/browse/RT-40325

    【讨论】:

      【解决方案2】:

      如果您怀疑存在泄漏,请先使用探查器对其进行识别来修复它。

      我重写了您的样本(顺便说一句,它没有显示任何数据),似乎没有泄漏。试试这个并检查控制台输出。

      import javafx.application.Application;
      import javafx.beans.property.SimpleStringProperty;
      import javafx.beans.property.StringProperty;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;
      
      public class MainLeak extends Application {
      
          private static final int iterations = 100;
          private static final int columns = 50;
          private static final int rows = 100;
      
          @Override
          public void start(Stage primaryStage) {
      
              TableView<ObservableList<StringProperty>> table = new TableView<>();
      
              Button button = new Button("button");
      
              button.setOnAction((actionEvent) -> {
      
                  addData( table, iterations);
      
      
              });
      
              addData( table, iterations);
      
              primaryStage.setScene(new Scene(new VBox(table, button), 800, 600));
              primaryStage.show();
          }
      
          private void addData( TableView table, int iterations) {
      
              for (int i = 0; i < iterations; i++) {
      
                  final int index = i;
      
                  addData(table);
      
                  System.gc();
      
                  System.out.println(index + ": free: " + Runtime.getRuntime().freeMemory() / 1024 + " kb, max: " + Runtime.getRuntime().maxMemory() / 1024 + " kb");
      
              }
      
          }
      
          private void addData(TableView table) {
      
              table.getItems().clear();
              table.getColumns().clear();
      
              for( int col=0; col < columns; col++) {
                  table.getColumns().add(createColumn(col));
              }
      
              for( int row=0; row < rows; row++) {
                  ObservableList<StringProperty> data = FXCollections.observableArrayList();
                  for( int col=0; col < columns; col++) {
                      data.add(new SimpleStringProperty(String.valueOf( row + " / " + col)));
                  }
                  table.getItems().add(data);
              }
          }
      
          private TableColumn<ObservableList<StringProperty>, String> createColumn(final int columnIndex) {
      
              TableColumn<ObservableList<StringProperty>, String> column = new TableColumn<>();
              String title = "Column " + columnIndex;
              column.setText(title);
              column.setCellValueFactory(cellDataFeatures -> cellDataFeatures.getValue().get(columnIndex));
      
              return column;
          }
      
          public static void main(String[] args) {
              launch(args);
          }
      }
      

      【讨论】:

      • 无。忘记删除了。感谢您的提示。
      • 感谢您的回复。我的代码没有显示任何数据,因为单元工厂不会影响泄漏。我运行了您的代码,每次按下按钮后,它都会稳定地泄漏旧代内存中的内存。我正在使用 JProfiler 来查找泄漏,这是显示老一代增加的屏幕截图:i.imgur.com/NJKQpMB.png
      猜你喜欢
      • 2015-01-23
      • 1970-01-01
      • 1970-01-01
      • 2016-08-29
      • 2013-08-16
      • 2017-03-06
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多