堆转储中不可能的Java内存引用
我在下午7:41进行了Java堆转储,我正在使用Eclipse内存分析工具进行分析。 堆转储包括20个会话对象。
在我的堆中的其中一个会话对象上使用Path to GC Roots命令显示以下3个对会话对象的引用。
- Finalizer线程拥有的“未完成”链表的终结器引用。 我的目标是排在第3位,最终确定。
- 来自消息处理程序线程的对会话对象的强引用,该消息处理程序线程本身是从计划在晚上7:11运行的清理TimerTask引用的。
- WeakHashMap $ Entry对会话对象的弱引用。 WeakHashMap通过静态强引用保持活动状态。
当会话对象仍然具有强引用和弱引用时,它如何才能在终结器队列中?
在剩余的19个会话对象中,还有1个在终结器队列中,并且具有类似的弱引用。 所有其他18个会话对象仅被弱引用。 为什么GC没有清除这些弱的参考?
几点概括:
- 对象只有在他们的弱引用被清除后才有资格完成(http://download.oracle.com/javase/6/docs/api/java/lang/ref/package-summary.html)
- 会话对象没有可以复活它的终结器,即使它已经完成,但是当对象仍处于其他对象后面的未终结队列中时,它无法运行。
- 我的应用程序不使用幻影引用,它是唯一一个对象有资格完成后应该能够存在的引用。 即使我的应用程序确实使用幻像引用,这些对象也不会公开它们对所持对象的引用。
我认为你在这里犯的错误就是这个部分:
Finalizer线程拥有的“未完成”链表的终结器引用。 我的目标是排在第3位,最终确定。
如果你在说这个:
static private Finalizer unfinalized = null;
在Sun的Finalizer.java
(一个Finalizer
包含一个next
和prev
Finalizer
,因此’链表’部分,对于那些在家里玩的人),那么这不是要完成的事情列表。
在最终化过程中,当对象无法访问时, Finalizer.add()
不是(我认为你假设的)被调用; 相反,该方法在Object的创建时被调用(例如,在
期间,通过本机代码,对于覆盖finalize()
任何Object。
next
链中存在终结器并不意味着它即将完成; 这是
static private ReferenceQueue queue
它拥有这样的对象。 在链表中只是意味着它有一个finalize()
方法。
因此,您的第一个点是红色鲱鱼,这是您保持项目可到达的第二个点,第三个点从第二个点流出(因为WeakReference
在对象可达时不会被清除)。
希望这可以帮助!
弱引用仅是GC的指示。 当它被清除时,你没有任何硬性保证。
您可以再次安排最终确定的对象。
我知道:
会话对象没有可以复活它的终结器,即使它已经完成,但是当对象仍处于其他对象后面的未终结队列中时,它无法运行。
然而,可能有其他对象这样做(即已经参与会话并获得自己的rez’d)。 无论哪种方式都显示该会话的终结者。
注意:在清除幻像之前,对象将不可用于最终确定。 (幻像引用最常用于安排预先清理操作, javadoc ),pre(不像弱者那样发布)。