在JavaFX 8中,保留中间绑定不被垃圾回收的推荐方法是什么?

20

简而言之: 垃圾回收正在清除我的活动绑定。

我有一个应用程序,使用JavaFX 2.2和Java 7成功开发和部署。

当我升级/转换到JavaFX 8.0(和Java 8)时,某些功能会在应用程序生命周期中“神秘地”停止工作,没有异常或其他指示错误状态的变化。例如:按钮停止工作,自定义单元格渲染器停止应用,启用/禁用状态停止更新。

经过多个小时的挖掘,我认为我已经追踪到了问题所在,这是由于JavaFX 8中的一些更改以及内部使用javafx.beans.WeakListener来处理在JavaFX 2.2中发现的内存泄漏。基本上,尽管它们控制的Node仍然处于活动状态,但我创建的管理数据状态依赖性的绑定正在被垃圾回收清除。

当我使用匿名类实例化绑定时,问题似乎最常见。我的一些问题可以通过将绑定存储为类成员的方式来修复,从而防止GC对其进行收集。我甚至曾经因为它们是通过FXML加载实例化的,从未直接引用过控制器(现在我总是将对控制器的引用塞到父节点的userData属性中)。

我的问题是:

  1. 相关的错误是非确定性的(或者至少是内存占用的功能)。
  2. 如果应该避免使用匿名类进行绑定,则需要在大型、现有代码库中查找每个实例以进行更改,这是很繁琐的工作。
  3. 即使我能找到每个实例,它也会极大地混杂代码。

令人沮丧的是,我似乎找不到Oracle文档中说“不要使用匿名类创建绑定”的任何内容,或者其他确保可靠使用绑定的指导方针。许多代码示例都使用了匿名类绑定。我也找不到关于如何正确更新JavaFX 2.2应用程序到JavaFX 8的任何说明。

非常感谢那些开发复杂JavaFX应用程序的人提供的任何建议(我已经开发了3年的JavaFX 2.x应用程序,并且开发了超过15年的Swing应用程序,所以这不是一个新手问题)。
注意:我的问题类似于清理JavaFX属性监听器和绑定(内存泄漏),但我想要具体而明确地知道如何使用复杂的绑定,并确保它们不会在随机时间被垃圾回收,而不必污染类与每个实例的引用。

2
你能详细说明一下“JavaFX 8的变化和javafx.beans.WeakListener的内部使用”吗?因为我不太了解这些(诚然,我拒绝深入研究fx 8之前的内容;-)- 根据我的经验,垃圾回收绑定始终是个麻烦... - kleopatra
1
对于那些寻找简单示例的人,请参见这个问题。你想要做的是使任何绑定的生命周期与依赖它的任何 UI 元素相同(这将会很棘手)。 - James_D
1
不可否认,我的代码在2.x版本中能够正常工作可能是一个误导;在Java 8中,GC行为和内存占用可能有足够的差异,从而产生影响。 - metasim
1
我并不感到惊讶,你在文档中找不到这样的警告。这意味着有人考虑过弱监听器的影响,如果有人考虑过,那么弱监听器的想法会立即被放弃。但是,嘿,我希望这是JavaFX设计中唯一的坏主意... - Holger
1
这种行为甚至在中间的Java版本8u11和8u20之间也略有改变:请参阅我的评论https://gist.github.com/jewelsea/5375786以获取更多背景信息。 - jewelsea
显示剩余8条评论
1个回答

3
弱事件处理程序应该允许GC回收监听器对象(如果没有其他引用),并在那时停止工作。正如你发现的那样,这意味着你必须在需要它继续触发时引用处理程序。这个要求与是否使用匿名类或普通类基本无关;如果使用普通类也会失败。
没有可能“自动”确定某个事件将不再被触发,这本质上是一个“修复”此问题的功能请求所需要的。如果您不想让任何内容被GC回收,可以将所有匿名监听器添加到存储为静态变量的列表中。如果您希望GC起作用(最终您会希望),则必须通过仅在需要时保留引用并在不再需要时释放它们来控制它。

这个问题有19个投票,而唯一的答案只有三个投票,尽管它被接受为解决方案。这似乎不成比例,让我对这个答案产生怀疑。很多人认为这个问题很好,但唯一的答案不太好吗?Atsby,自你回答这个问题以来已经过去了五年(显然也是你最后一次出现在这里),你是否意识到你的答案存在任何弱点? - pateksan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接