情况1
鉴于myListener
“不使用其他任何地方”,因此我认为,一个[方法- ]局部变量,答案是否定的。 虽然在一般情况下,答案多半是没有 ,但有时是肯定的 。
只要myListener
是强可到达,那么它永远不会成为资格定稿,并会继续消耗内存。 例如,这将是情况下,如果myListener
是一个“正常”声明static
变量(*在Java中所有的“正常”的引用是强引用*)。 但是,如果myListener
是一个局部变量,那么对象将是不可到达之后再目前的方法调用和返回bool.removeListener(myListener)
是有点意义的过度工程。 无论是观察者和Observable
超出范围,并最终敲定。 从我自己的一个报价的博客文章关于这个答案可能描绘出更好的画面:
如果你把盒子放在海洋不要紧,如果箱子知道它里面的猫。 如果盒子是不可达的,也不是猫。
理论
要充分这里了解情况,我们要提醒一个Java对象(的生命周期的自我源 ):
一个对象是强可如果它可以通过一些线索,而无需遍历任何参照物来达到。 新创建的目的是通过创建它的线程强可到达。 [..]一个目的是弱可如果是[未]强烈[..]可到达,但可以通过遍历弱引用到达。 当一个弱可到达对象的弱引用被清除,对象就符合定稿。
在静态变量的情况下,这些将始终可以访问,只要类被加载,从而到达。 如果我们不希望的静态引用是阻碍垃圾收集器做他的工作之一,那么我们就可以宣布使用一个变量WeakReference
代替。 JavaDoc的说:
弱引用对象[..]不禁止其指示正在变得可终结,并被终结,然后被回收。 [..]假设垃圾回收器确定在某一时间点,对象是弱可。 那时它将原子清楚,对象的所有弱引用[..]。 同时,它会声明所有以前的弱可到达的对象是终结。
显式管理
为了说明,让我们假设我们写了一个JavaFX的空间模拟游戏。 每当一个Observable
的行星移动到飞船的旁观者的看法,游戏引擎注册与地球的飞船。 这是很明显的是,无论何时行星超出视图,游戏引擎应该还通过使用除去宇宙飞船作为行星的观察者Observable.removeListener()
否则,飞船继续通过空间飞行,内存就会泄漏。 最终,本场比赛不能处理500颗十亿观测行星,这将有崩溃OutOfMemoryError
。
请注意,对于绝大多数的JavaFX的听众和事件处理程序,他们的生命周期是平行于它们的Observable
这样的应用程序开发人员有什么可担心的。 例如,我们可以构建一个TextField
以及与文本字段的注册textProperty
是验证用户输入的监听器。 只要文本字段支左右,我们希望听众留下来。 迟早,文本字段不再使用,并收集垃圾时,他,验证侦听也是垃圾收集。
自动管理
要继续在太空模拟例子,假设我们的游戏有多人有限的支持,所有的球员需要观察对方。 也许每个玩家击杀保持度量的本地记分牌或者他们需要观察广播的聊天消息。 原因是不是这里的重要的一点。 当玩家退出游戏,会发生什么? 显然,如果听众没有明确管理( 删除 ),那么谁退出播放器不会成为资格定稿。 其他玩家的将保持很强的参考离线玩家。 明确去除听众仍然是一个有效的选项,以及可能为我们的游戏中最首选的,但让我们说,感觉有点突兀,我们希望找到一个更漂亮的解决方案。
我们知道,游戏引擎保持强引用到所有在线玩家,只要他们是在网上。 因此,我们希望飞船听更改或只为只要游戏引擎保持强引用对方的事件。 如果你看过“理论”部分,那么可以肯定一个WeakReference
听起来像一个解决方案。
然而,仅仅在WeakReference的包装的东西是不完整的解决方案。 但很少有人做得到。 的确,当最后一个强引用了“参照物”设置为null
或以其他方式变得不可,指涉将有资格进行垃圾回收( 假设指涉不能使用达到SoftReference
)。 但WeakReference的仍然是游逛。 应用程序开发人员需要添加一些管道,以便WeakReference的本身是从他被放在数据结构中删除。如果没有,那么我们可能已经减少了内存泄漏,但内存泄漏仍然存在的严重程度,因为动态添加弱引用占用内存过多。
我们是幸运的,JavaFX的添加界面WeakListener
和类WeakEventHandler
为“自动清除”的机制。 所有相关类的构造函数接受真正的监听器/处理器由客户端代码提供,但它们存储使用弱引用侦听器/处理器。
如果你看一下的JavaDoc WeakEventHandler
,你会发现,类实现EventHandler
,所以可以使用WeakEventHandler地方的事件处理程序的预期。 同样地,一种已知的实施WeakListener
何一个可以用来InvalidationListener
或ChangeListener
预期。
如果你看看源代码WeakEventHandler
,你会发现,类基本上只有一个包装。 当他的指涉( 真正的事件处理程序 )是垃圾回收时, WeakEventHandler
“停止工作”,由没有做任何事情的时候WeakEventHandler.handle()
被调用。 该WeakEventHandler
不知道哪个对象,他已经迷上了,即使他这样做了,拆除的事件处理程序的不均质。 所有已知的实现类WeakListener
具有虽然竞争优势。 当它们的回调函数被调用时,他们或明或暗地提供给参考Observable
它们与注册。 因此,一个的指涉时WeakListener
被垃圾回收,最终WeakListener
实施将确保该WeakListener
本身从去除Observable
。
如果不是已经很清楚,我们的空间模拟游戏的解决办法是让游戏引擎使用到所有在线飞船强引用。 当飞船上线,所有其它网络的太空船正在与新的播放器使用弱听者注册如WeakInvalidationListener
。 当玩家下线后,游戏引擎中删除他的强有力的参考玩家与玩家将有资格进行垃圾回收。 游戏引擎没有理会明确去除离线玩家作为其他玩家的监听器。
案例2
号为了更好地理解我要说些什么未来,请先阅读我的情况下1回答。
BooleanPropertyBase
存储的强引用otherBool
。 这本身不会导致otherBool
始终是可达的,从而潜在地引起了内存泄漏。 当bool
变得无法访问,那么这样做的所有的存储引用( 假设他们不存储任何其他地方 )。
BooleanPropertyBase
也适用加入自己作为一个Observer
,你绑定它的属性。 然而,通过在工作几乎完全一样的一类包装本身并没有那么WeakListener
在我的情况进行了说明1个回答。 所以,一旦你废掉bool
后,将其从删除之前只是时间问题otherBool
。
我完全同意的情况下1回答同意,但案件2是比较麻烦一些。 The bool.unbind()
调用是必要的。 如果ommitted,但它会导致小的内存泄漏。
如果您运行下面的循环,应用程序将最终耗尽内存。
BooleanProperty p1 = new SimpleBooleanProperty();
while(true) {
BooleanProperty p2 = new SimpleBooleanProperty();
p2.bind(p1)
}
该BooleanPropertyBase,intenally,不使用真实WeakListener(的实现WeakListener接口),它使用的是半生不熟的解决方案。 所有的“P2”情况下获得最终垃圾回收,但听者持有空了WeakReference永远留在记忆每个“P2”。 这同样适用于所有属性,不仅BooleanPropertyBase。 它在这里解释详细,和他们说,这是固定在Java中9。
在大多数情况下,你没有注意到此内存泄漏,因为它留下的只有几十个字节,每绑定一直没有解除绑定。 但在某些情况下,它给我带来真正的麻烦。 一个很好的例子是被频繁更新的表的表格单元格。 然后将细胞重新绑定到不同的属性所有的时间,而在记忆这些剩余配音迅速积累。