堆转储中不可能的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包含一个nextprev Finalizer ,因此’链表’部分,对于那些在家里玩的人),那么这不是要完成的事情列表。

在最终化过程中,当对象无法访问时, Finalizer.add()不是(我认为你假设的)被调用; 相反,该方法在Object的创建时被调用(例如,在期间,通过本机代码,对于覆盖finalize()任何Object。

next链中存在终结器并不意味着它即将完成; 这是

 static private ReferenceQueue queue 

它拥有这样的对象。 在链表中只是意味着它一个finalize()方法。

因此,您的第一个点是红色鲱鱼,这是您保持项目可到达的第二个点,第三个点从第二个点流出(因为WeakReference在对象可达时不会被清除)。

希望这可以帮助!

弱引用仅是GC的指示。 当它被清除时,你没有任何硬性保证。

您可以再次安排最终确定的对象。

我知道:

会话对象没有可以复活它的终结器,即使它已经完成,但是当对象仍处于其他对象后面的未终结队列中时,它无法运行。

然而,可能有其他对象这样做(即已经参与会话并获得自己的rez’d)。 无论哪种方式都显示该会话的终结者。

注意:在清除幻像之前,对象将不可用于最终确定。 (幻像引用最常用于安排预先清理操作, javadoc ),pre(不像弱者那样发布)。