Java – 匿名内部生命周期

当在对象生命周期的哪个点使用匿名内部类作为PropertyChangeListener时,是否收集了类垃圾? 收回包含类(SettingsNode)后? 我应该在包含类(SettingsNode)的终结器中显式删除PropertyChangeListener吗?

public class SettingsNode extends AbstractNode { public SettingsNode(Project project, ProjectSettings projectSettings) throws IntrospectionException { // use an anonymous inner class to listen for changes projectSettings.addPropertyChangeListener(ProjectSettings.PROP_NAME, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { // handle event } }); } } 

与所有对象一样,匿名内部类有资格在最后一次引用它时不再引用垃圾。 我在这里使用weasel措辞,因为Java并不能保证事情会被GC化 – 唯一的保证就是只要有引用它就不会发生。

在这种特殊情况下,当projectSettings执行removePropertyListener()或者本身是垃圾收集时。

因为projectSettings引用了匿名内部类,并且因为内部类引用了它的包含类,这意味着包含类也将至少与内部类一样长。

您正在将要创建的PropertyChangeListener类添加到projectSettings对象。 只要projectSettings引用它,就不会收集PropertyChangeListener。

在示例中,您已显示设置节点,并且在回收项目设置之前无法回收侦听器。

您将需要显式删除侦听器,但您应该寻找比终结器更可靠的地方。

在删除PropertyChangeListener之后,才会回收SettingsNode。 对侦听器使用匿名类会导致内存泄漏的常见原因。

编辑Alex B的问题:

如果projectSettings在应用程序的生命周期中存在,则无法删除匿名侦听器,因为在注册后没有对它的引用。 在创建多个SettingsNode实例时,它们将在构造函数中添加它们的侦听器,但它们永远不会被删除,因为没有其他人具有对它们的引用。 这将阻止SettingsNodes被删除,并且侦听器也会引用SettingsNodes

这个问题已经过时了。

但是,我不同意这里的大部分答案。

无需显式删除侦听器。 在这种情况下,内部类PropertyChangeListener对象将一直存在,直到收集包含的实例SettingsNode。

您实际上无法删除PropertyChangeListener对象,因为没有为它保留引用。

虽然PropertyChangeListener对象引用其包含的对象SettingsNode,但这并不会阻止包含对象被取消引用和垃圾回收。

一旦取消引用包含对象,SettingsNode包含的所有对象就变成“隔离岛”。 所有这些都将被垃圾收集。

内存泄漏的典型场景。 不建议最终确定,因为它可能会延迟GC.You可能会暴露清理function或覆盖处置和取消注册。

真的很惊讶为什么挥杆没有内置弱听众注册。 可能你可以尝试在source forge中使用一些开源软件吗?