当使用匿名内部类作为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
}
});
}
}
答案 0 :(得分:7)
与所有对象一样,匿名内部类可以在最后一次引用它时不再引用它时收集垃圾。我在这里使用weasel措辞,因为Java并不能保证事情会被GC化 - 唯一的保证就是只要有参考就不会发生。
在这种特殊情况下,那就是当projectSettings
执行removePropertyListener()
或者本身是垃圾收集时。
因为projectSettings
引用了匿名内部类,并且因为内部类引用了它的包含类,这意味着包含类也将至少与内部类一样长。
答案 1 :(得分:2)
您正在将要创建的PropertyChangeListener类添加到projectSettings对象。只要projectSettings引用它,就不会收集PropertyChangeListener。
答案 2 :(得分:2)
在示例中,您已显示设置节点,并且在回收项目设置之前无法回收侦听器。
您需要显式删除侦听器,但您应该寻找比终结器更可靠的地方。
在删除PropertyChangeListener之后,才会收回SettingsNode。对侦听器使用匿名类会导致内存泄漏的常见原因。
编辑Alex B的问题:
如果projectSettings在应用程序的生命周期中存在,则无法删除匿名侦听器,因为在注册后没有对它的引用。 在创建多个SettingsNode实例时,它们将在构造函数中添加它们的侦听器,但它们永远不会被删除,因为没有其他人具有对它们的引用。这将阻止SettingsNodes被删除,并且侦听器也会引用SettingsNodes
答案 3 :(得分:1)
这个问题很陈旧。
但是,我不同意这里的大部分答案。
无需显式删除侦听器。在这种情况下,内部类PropertyChangeListener对象将一直存在,直到收集包含的实例SettingsNode为止。
您实际上无法删除PropertyChangeListener对象,因为没有为它保留引用。
虽然PropertyChangeListener对象引用其包含的对象SettingsNode,但这并不会阻止包含对象被取消引用和垃圾回收。
一旦取消引用包含对象,SettingsNode包含的所有对象就变成“隔离岛”。所有这些都将被垃圾收集。
答案 4 :(得分:0)
内存泄漏的典型场景。不建议最终确定,因为它可能会延迟GC.You可以暴露清理功能或覆盖处置和取消注册。
真的很惊讶为什么swing没有内置弱听众注册。可能你可以在source forge中尝试一些开源?