1

我正在设计一个 JavaFX 应用程序。我已决定加载用于动态收集用户输入(来自 FXML)以响应用户事件(例如单击按钮)的对话框表单/窗口,然后在用户完成时“卸载”窗口形成并驳回它。

加载每个 FXML 表单后,在向用户显示对话框之前,需要初始化列表视图、表格视图和组合框。这是我为此目的使用的一些代码:

@FXML // This method is called by the FXMLLoader when 
      //initialization is complete

void initialize() {

    // Initialize your logic here: all @FXML variables will have been injected

    ObservableList<Institution> ilist = Institution.getInstitutionList();
    Callback<ListView<Institution>, ListCell<Institution>> cellfactory =
            new Callback<ListView<Institution>, ListCell<Institution>>() {
                @Override
                public ListCell<Institution> call(ListView<Institution> p) {
                    return new InstitutionListCell();
                }
            };

    cbxInst.setCellFactory(cellfactory);
    cbxInst.setButtonCell(cellfactory.call(null));
    cbxInst.setPromptText(CensusAssistant.RES_STRING_INSTSELECT);
    cbxInst.setItems(ilist);
    cbxInst.setDisable((ilist.size() < 1));


    Callback<ListView<Rotation>, ListCell<Rotation>> rotfactory =
            new Callback<ListView<Rotation>, ListCell<Rotation>>() {
                @Override
                public ListCell<Rotation> call(ListView<Rotation> p) {
                    return new EncRotationListCell();
                }
            };
    :
    :

我不想显示所有代码。这里的重点是,对于我的表单上使用 Cell 子类(ListCell 等)的每个控件,我都使用匿名内部类来提供单元工厂。

这些匿名内部类将持有对其封闭类的引用。我的结论是,这些引用将防止表单在用户关闭表单后的任何时候被垃圾收集。那么,我担心如果在会话中多次打开和关闭表单,则会出现内存泄漏问题。

我在这方面有目标吗?当用户关闭表单时,我是否需要编写将单元工厂与控件分离的代码?一般来说,这是事件侦听器(或通常通过使用内部类解决的任何问题)的问题吗?在释放对象之前始终取消注册事件或操作处理程序是否明智?

编辑:

这篇文章中已经处理了许多相同的问题:使用(匿名)内部类究竟什么时候可以安全泄漏?.

我想我倾向于相信,在这种情况下,窗口可能会被反复构造和关闭,我需要尝试消除对 JavaFX 控制器类的任何潜在的长期引用;尤其是细胞工厂。

4

1 回答 1

1

Java垃圾收集的快速介绍。这是一个可能与您拥有的对象树相似的对象树:

Window
   |-- AnchorPane
            |-- ListView
            |-- Label

我不是想完全复制它,这只是一个例子。现在,如果我们从 Window 中移除 AnchorPane,最终将收集到 AnchorPane、ListView 和 Label,而不是内存泄漏。现在,如果您将对 AnchorPane 的引用传递给另一个对象,那么您需要删除两个引用才能回收对象。

我发现尝试设计一种不会导致内存泄漏的代码开发方法,然后测试不可避免的错误会更容易。


考虑它的最佳方法是对象的寿命。如果窗口的内容被切换为不同的表单,则窗口的寿命将比内容长。您的某些域对象和服务的寿命也可能比内容长。计算出对象的相对寿命后,您可以遵循以下规则:

短期对象可以引用长期对象,但反之则不行。

在示例中,如果 ListView 有对 Window(寿命更长的对象)或 Label(寿命相等的对象)的引用,则不会导致内存泄漏。因为 Window 引用了更​​短的 AnchorPane,我们必须手动将其从 Window 子项中删除。对于任何长短参考,您都必须手动删除它,这是一个错误的机会,所以有时您必须这样做,但最好尽量减少这些关系。

对于您不拥有代码的绑定和场景图,最好假设您必须始终手动删除这些引用,因为执行的内容引用了可能会更改的内容。

于 2013-05-03T23:11:54.757 回答