VirtualFlow 中的 JavaFX 内存泄漏?

2023-12-06

我在 VirtualFlow 中遇到了一种行为,不确定这是否是内存泄漏或者是否是这样设计的。

在 TableView 中,我希望当不使用 TableRow 实例时,它们应该能够被垃圾收集。但是,当我按照以下步骤操作时:

Step #1:我打开了一个带有 TableView 的阶段,其中没有数据。我检查了内存中是否有 TableRow 的实时实例,但没有看到任何实例(这是我所期望的)。

Step #2:我用一些数据填充了 TableView,这会根据所需的空间生成 TableRows。在我的场景中,假设它生成了 38 个 TableRow 对象的实例。

Step #3:我清除了 TableView 中的项目并显示占位符消息。当我检查 TableRow 实例时(执行多次 GC 后),它仍然具有 VirtualFlow 中强烈保留的 TableRows 的所有 38 个引用cellsArrayLinkedlist,如下图所示:

enter image description here

这是内存泄漏还是已经考虑到的预期行为?

这是我用来检查上述场景的代码:

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableViewMemoryLeakDemo extends Application {

    public static void main(String... a) {
        Application.launch(a);
    }

    @Override
    public void start(final Stage primaryStage) {
        final ObservableList<TableDataObj> items = FXCollections.observableArrayList();
        final TableView<TableDataObj> table = buildTable();
        table.setItems(items);

        Button clear = new Button("Clear All");
        clear.setOnAction(e -> {
            items.clear();
        });

        Button add = new Button("Add 50 Rows");
        add.setOnAction(e -> {
            for (int i = 0 + 1; i < 50; i++) {
                final String firstName = "First Name " + i;
                final String lastName = "Last Name " + i;
                final String city = "City " + i;
                items.add(new TableDataObj(i, firstName, lastName, city));
            }
        });
        HBox row = new HBox(add, clear);
        row.setSpacing(10);

        final VBox root = new VBox(row, table);
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        VBox.setVgrow(table, Priority.ALWAYS);

        final Scene sc = new Scene(root, 1200, 950);
        primaryStage.setScene(sc);
        primaryStage.setTitle("TableView MemoryLeak Demo " + System.getProperty("javafx.runtime.version"));
        primaryStage.show();
    }

    private TableView<TableDataObj> buildTable() {
        final TableColumn<TableDataObj, Integer> idCol = new TableColumn<>();
        idCol.setText("Id");
        idCol.setCellValueFactory(param -> param.getValue().idProperty().asObject());
        idCol.setPrefWidth(100);

        final TableColumn<TableDataObj, String> fnCol = new TableColumn<>();
        fnCol.setText("First Name");
        fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
        fnCol.setPrefWidth(150);

        final TableColumn<TableDataObj, String> lnCol = new TableColumn<>();
        lnCol.setText("Last Name");
        lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
        lnCol.setPrefWidth(150);

        final TableColumn<TableDataObj, String> cityCol = new TableColumn<>();
        cityCol.setText("City");
        cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
        cityCol.setPrefWidth(150);

        final TableView<TableDataObj> tableView = new TableView<>();
        tableView.getColumns().addAll(idCol, fnCol, lnCol, cityCol);
        return tableView;
    }

    /**
     * Data object.
     */
    class TableDataObj {
        private final IntegerProperty id = new SimpleIntegerProperty();
        private final StringProperty firstName = new SimpleStringProperty();
        private final StringProperty lastName = new SimpleStringProperty();
        private final StringProperty city = new SimpleStringProperty();

        public TableDataObj(final int i, final String fn, final String ln, final String cty) {
            setId(i);
            setFirstName(fn);
            setLastName(ln);
            setCity(cty);
        }

        public StringProperty cityProperty() {
            return city;
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public int getId() {
            return id.get();
        }

        public IntegerProperty idProperty() {
            return id;
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

        public void setCity(final String city1) {
            city.set(city1);
        }

        public void setFirstName(final String firstName1) {
            firstName.set(firstName1);
        }

        public void setId(final int idA) {
            id.set(idA);
        }

        public void setLastName(final String lastName1) {
            lastName.set(lastName1);
        }
    }
}

正如上面的评论和插图中所指出的here,许多 JavaFX 视图组件提供蝇量级渲染:调用工厂方法创建少量可重复用于渲染的实例visible内容。TableView通常只需要one TableRow每个可见(或部分可见)行。最大化封闭阶段说明了这种效果。作为@James_Dobserves,“这肯定是预期的行为吗?”

In normal use, the underlying data would be updated in situ, as shown in your example. Should the need arise in the larger context of VirtualFlow, the variation below adds a Refresh button to examine the effect of invoking refresh() on the table. This allows unused table rendering apparatus to be collected in a future pass. As a test, enlarge the stage, and note the larger number of rows. Shrink the stage, click Refresh and request garbage collection. Note the reduced number of TableRow instances.


import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * @see https://stackoverflow.com/q/76487091/230513
 */
public class TableViewLeak extends Application {

    public static void main(String... a) {
        Application.launch(a);
    }

    @Override
    public void start(final Stage primaryStage) {
        final ObservableList<TableDataObj> items = FXCollections.observableArrayList();
        final TableView<TableDataObj> table = buildTable();
        table.setItems(items);

        Button add = new Button("Add 50 Rows");
        add.setOnAction(e -> {
            for (int i = 0 + 1; i < 50; i++) {
                final String firstName = "First Name " + i;
                final String lastName = "Last Name " + i;
                final String city = "City " + i;
                items.add(new TableDataObj(i, firstName, lastName, city));
            }
        });
        Button clear = new Button("Clear All");
        clear.setOnAction(e -> {
            items.clear();
        });
        Button remove = new Button("Refresh");
        remove.setOnAction((e) -> {
            table.refresh();
        });

        HBox row = new HBox(add, clear, remove);
        row.setSpacing(10);
        final VBox root = new VBox(row, table);
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        VBox.setVgrow(table, Priority.ALWAYS);

        final Scene sc = new Scene(root);
        primaryStage.setScene(sc);
        primaryStage.setTitle("TableView MemoryLeak Demo "
            + System.getProperty("javafx.runtime.version"));
        primaryStage.show();
    }

    private TableView<TableDataObj> buildTable() {
        final TableColumn<TableDataObj, Integer> idCol = new TableColumn<>();
        idCol.setText("Id");
        idCol.setCellValueFactory(param -> param.getValue().idProperty().asObject());
        idCol.setPrefWidth(100);

        final TableColumn<TableDataObj, String> fnCol = new TableColumn<>();
        fnCol.setText("First Name");
        fnCol.setCellValueFactory(param -> param.getValue().firstNameProperty());
        fnCol.setPrefWidth(150);

        final TableColumn<TableDataObj, String> lnCol = new TableColumn<>();
        lnCol.setText("Last Name");
        lnCol.setCellValueFactory(param -> param.getValue().lastNameProperty());
        lnCol.setPrefWidth(150);

        final TableColumn<TableDataObj, String> cityCol = new TableColumn<>();
        cityCol.setText("City");
        cityCol.setCellValueFactory(param -> param.getValue().cityProperty());
        cityCol.setPrefWidth(150);

        final TableView<TableDataObj> tableView = new TableView<>();
        tableView.getColumns().addAll(idCol, fnCol, lnCol, cityCol);
        return tableView;
    }

    /**
     * Data object.
     */
    private static final class TableDataObj {

        private final IntegerProperty id = new SimpleIntegerProperty();
        private final StringProperty firstName = new SimpleStringProperty();
        private final StringProperty lastName = new SimpleStringProperty();
        private final StringProperty city = new SimpleStringProperty();

        public TableDataObj(final int i, final String fn, final String ln, final String cty) {
            setId(i);
            setFirstName(fn);
            setLastName(ln);
            setCity(cty);
        }

        public StringProperty cityProperty() {
            return city;
        }

        public StringProperty firstNameProperty() {
            return firstName;
        }

        public int getId() {
            return id.get();
        }

        public IntegerProperty idProperty() {
            return id;
        }

        public StringProperty lastNameProperty() {
            return lastName;
        }

        public void setCity(final String city1) {
            city.set(city1);
        }

        public void setFirstName(final String firstName1) {
            firstName.set(firstName1);
        }

        public void setId(final int idA) {
            id.set(idA);
        }

        public void setLastName(final String lastName1) {
            lastName.set(lastName1);
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VirtualFlow 中的 JavaFX 内存泄漏? 的相关文章

  • 带有地图的 JavaFX TableView 对象

    因此 我对 JavaFx TableView 进行了一些挖掘 并找到了一些针对简单情况的不错的解决方案 This article http docs oracle com javafx 2 ui controls table view ht
  • JavaFX 打印自定义纸张尺寸

    在 JavaFX 中 我想将照片打印到 10x15 的纸张上 有一些纸张常数 但没有 100x150 mm 常数 是否可以创建自己的纸张以在页面布局中使用它 Thanks PageLayout pageLayout printer crea
  • JavaFX - setVisible 隐藏元素但不重新排列相邻节点

    在 JavaFX 中 如果我有一个场景有 2VBox元素和每个VBox有多个Label in it 如果我设置顶部VBox to 无形的 为什么底部VBox 不向上移动顶部的场景VBox was The VBox is 无形的但我希望其他物
  • 在JavaFX中如何在表视图中添加带有数据的组合框

    我已经尝试了很多 但无法将数据库中的所有值填充到我的组合框表格单元格中 控制器 java public class controller GetConnection gc new GetConnection PreparedStatemen
  • Java - ZUI(可缩放用户界面)

    我目前正在做一个小型个人项目 需要显示极其大量的数据 我突然想到实现一种可缩放的用户界面 以允许用户在大量数据中导航 我知道现有的项目 例如ZVTM http zvtm sourceforge net and 短笛2d https code
  • 如何使用 JRE 部署 JavaFX 11 桌面应用程序

    我有一个 JavaFX JDK 8 桌面业务应用程序 它使用 Java Web Start 进行部署 用户安装了 Java 8 只需访问 URL 我的 AWS Linux 服务器上的公共 URL 即可下载 启动应用程序 使用 Web Sta
  • 为什么禁用阶段可调整大小在 javafx 中不起作用?

    当我尝试setResizable对于我在 javaFX 应用程序中的场景 它不起作用 我仍然可以更改窗口大小 这是我的测试应用程序的代码 Override public void start Stage stage throws Excep
  • 仅当用户开始输入时清除 JavaFX TextField 中的提示文本

    默认行为是当字段获得焦点时 字段中的提示文本将被删除 那是标记在场上的时候 是否可以配置文本字段 以便仅在用户开始输入时删除提示文本 否则 我需要在每个文本字段旁边 上方添加一个标签 以描述其中的值 我知道它有点旧 但我自己也需要它 这仍然
  • Mac 上的 JavaFX WebView 字体问题

    有些网站显示乱码而不是正确的文本 它只发生在 Mac 上 For example with GMapsFX 可能与 OS X 10 11 或 10 12 有关 我用Java 1 8 0 121测试了它 此问题有任何修复或解决方法吗 就我而言
  • 如何调整Javafx未装饰阶段的大小?

    我是JavaFX技术的新手 目前我正在开发javafx应用程序 其中有未装饰的阶段 我能够使用下面的代码将其移动到屏幕上 但我是无法从右下角调整此窗口的大小 任何人都可以建议我解决方案 public void loadPanel final
  • JavaFX - 如何从另一个控制器使用一个控制器中的方法?

    使用场景构建器 我有 2 个阶段 每个阶段都有一个控制器 stage1Controller stage2Controller Stage1控制器 public class Stage1Controller FXML private Menu
  • 如何在 Java FX 中以编程方式模拟箭头键按下

    我想让我的 JFX 应用程序模拟箭头键按下 当它们在 TextField 中注册时 但我不知道如何发送字符串或字节以外的任何内容 我正在想象这样的事情 static EventHandler
  • JavaFX 多线程 - 连接线程不会更新 UI

    我正在尝试创建一个加载程序对话框 用户可以在其中知道程序正在加载所请求的内容并且程序正在按预期运行 但正因为如此 我需要join 解析器线程和之前继续主线程 这使得对话框空白 解析器任务 java public class ParserTa
  • javaFX helloworld jar 无法在不同平台上运行

    我对 JavaFX 很陌生 不确定是否有人知道我做错了什么 这是场景 在win 7上 使用netbeans 8和jdk1 8 0 05创建了一个helloworld jar 在 win 7 上 java jar helloworld jar
  • 如何修复 fxml 中的“无法派生 .jar 文件的模块描述符”错误

    我想从 JAR 库获取图像到我的项目中
  • 如何理解JavaFX三角形网格?

    只是想了解有关三角形网格的 JavaFX 文档 这段代码可以工作并绘制一个矩形 public class Shape3DRectangle extends TriangleMesh public Shape3DRectangle float
  • 在 JavaFX 中如何在屏幕上移动精灵?

    我是 JavaFX 新手 正在尝试编写一个游戏 其中动画 2D 角色在屏幕上行走 例如原始的 塞尔达传说 游戏 我在 Swing 中完成了此操作 方法是创建自己的 Sprite 类并重写 Swing 中的 PaintComponent 方法
  • JavaFX 图表自动缩放错误且数字较低

    我正在使用 JavaFX 构建 StackedBarChart 随着新数据的进入 图表将发生变化 我使用更新图表的按钮来模拟这一点 它大部分工作正常 但我注意到 当我第一次更新图表时 如果值较低 值小于 100 Y 轴标签似乎有点偏离 更奇
  • 如何隐藏TabPane中的TabBar?

    我正在尝试使用构建下一个 上一个窗口TabPane 我决定使用TabPane因为它易于使用和设计场景生成器 在应用程序启动时 我用它来隐藏TabBar目前 tabPane setTabMinHeight 10 tabPane setTabM
  • JDK 11/JavaFX:如何在没有构建/依赖管理的情况下制作胖罐子?

    我认为不用说 我应该能够使用 Oracle 自己的 JDK 和 JavaFX 来自 gluonhq 来构建用户可以使用的可分发 jar 文件 经过详尽的搜索 大量阅读 过去几个月 24 小时或更长时间 最后是这个 Google 搜索查询 h

随机推荐