GC与幽灵引用

网上摘录一篇文章,来自http://qing.weibo.com/2095854040/7cec31d8330008rw.html内容如下,顺带自己体会:

 1、WeakReference/SoftReference,在GC时,如果这个Reference所引用的对象可以被回收,collector会首先将Reference.referent域直接清除(不通过调用clear()方法)。而后,才将Reference进行Enqueue操作,进入到构造时指定的ReferenceQueue中。

2、所有Reference状态发生改变时,collector首先将这些对象全部加入到一个pending的链表中,然后通知Reference Handler线程进行处理,Reference Handler线程负责对pending链表中的每一个Reference进行ENQUEUE操作(有队列的)。

3、Finalizer是一种特殊的Reference,很遗憾,在Java文档中没有正式提及。Finalizer在ENQUEUE之前是没有clear referent的,这使得Finalizer线程可以对referent对象调用finalize方法。在执行了finalize方法后,referent将被清除。由于这类对象的Finalizer引用实在构造时创建的,因此,执行了一次finalize方法后,这个Finalizer引用就被GC释放了,不会再次执行。

4、如果一个对象,有finalize方法及WeakReference,那会是怎么样呢?有一个很奇怪的事情可能会发生:那就是GC时,WeakReference会clear掉,而后Finalizer会ENQUEUE、执行finalize方法。如果在finalize方法中让对象恢复强引用,那么,很不幸的事情发生:这个WeakReference已经不再真实反映了,实际的对象没有GC掉,但WeakReference已经被清除了。(应该说,我不认为这是JVM Spec的Bug) 今天遇到一个非常奇怪的现象,在Solaris上的JDK1.6,居然在运行时出现了很多的Finalizer对象,却没有及时的被GC掉,而且Full GC也没有将这些对象GC掉(这些对象已经不再存在其他的root-reference)。当然,在一个更晚的时间点,这些对象是已经被GC掉了。从 heap的分析来看,collector是实际上已经将这些对象挂接到了reference pending链 表中,可惜的是,却没有进行notify操作,使得这些本来应该提早就进行回收的对象不断的延迟。不太清楚这是不是Solaris上的JVM的一个 Bug,反正对我们系统的性能来说,是有一定的影响的,导致了GC效率是存在一定程度上的降低。在Linux上没有发现这个问题。  

 

对于1,如果是PhantomReference应该也是适用的。

对于2,可以参照Reference中的代码看,pending列表按照代码说明,确实是垃圾回收器干的

对于3,很诡异,因为Finalizer在我运行的demo看,同时存在PhantomReference情况下,先是做Finalize行为,然后才是PhantomReference,这里面确实如上文所说的,Finalizer是特殊的Reference,并且也有ENQUEUE的行为,但是很奇怪,难道存在多个Reference下,也是有优先级的么?

对于4,我也遇见过,但是WeakReference应该一般清除不了吧,除非认为设置NULL。

 

结论,总之,这块涉及到垃圾回收和JVM内部行为,研究起来还是很有趣的一件事情,那位仁兄又更好的链接和知识可以教我一下。

posted @ 2012-08-27 16:38  规格严格-功夫到家  阅读(316)  评论(0编辑  收藏  举报