我知道GC会收集没有引用指向相关对象的对象,但是在侦听器对象的情况下会发生什么?
假设您有一个AnimationDelegate
来监听来自DataSupplier
的数据。当DataSupplier
收到数据并将事件触发到AnimationDelegate
时,代理人将使Graphic
无效(/更新/重绘等...)。现在说屏幕被禁用,删除或通过各种方式,图形不再绘制和收集。 AnimationDelegate
仍在DataSupplier
注册。 GC如何知道收集它?是否应该在图形finalize()
方法中取消注册委托?
答案 0 :(得分:3)
我担心答案不符合格式:)从Brian Goetz开始this article:如果你对GC感兴趣,他是一个完美的读者。
基本上,只要对象无法从活动线程中访问,就会收集它。即使在一个JVM中,实际算法也会有所不同,但这一点保持不变:无法访问的是垃圾。什么是可达的不是垃圾。容易。
GC不会在您的示例中收集Graphic
,因为它可以从AnimationDelegate
访问,而DataSupplier
可以从finalize()
到达(通过订阅),这可以从某些人访问活跃的线程。所以答案是:你的假设是错误的; GC不会在这里收集任何东西。
要回答您的问题,请取消订阅您不需要的所有内容。
正如@rfeak正确地说,finalize()
是一个很大的禁忌。几乎不可能正确地使用它,并且它太容易使用它错了。也就是说,当您需要释放资源时,可以将其用作备份解决方案。但通常你的应用程序必须才能正常工作,即使{{1}}永远不会被调用。
答案 1 :(得分:2)
这完全取决于您使用的JVM和GC。来自JDK的大多数默认GC使用所谓的“跟踪收集器”,它只是从给定的 root 对象集开始,并跟踪从该集可到达的所有对象。内存中的所有其他对象都被视为垃圾并被删除。因此,除非可以从根集中访问其中一个对象,否则循环引用并不是真正的问题。
对象的根集是什么?好吧,如果内存服务正确的根可以在:程序寄存器,每个线程的堆栈中的局部变量和静态变量。
要查看您的对象是否为GC,我们会更多地了解您的应用程序的设计。
@Edit:哦,我差点忘了:http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf 这是对它如何运作的非常好的概述。
答案 2 :(得分:0)
只会知道你是否删除了引用(将其删除)。
但是,不要在finalize()上执行此操作。敲定是糟糕的坏事。应该有其他生命周期方法可用于清理侦听器(观察者)类型对象。
顺便说一句,观察者模式因创建内存泄漏而臭名昭着,因为GC由于延迟引用而无法收集。