weakreference实现原理分析

前言

若干年前看了Java的四种引用类型,只是简单知道了不同类型的作用,但对其实现原理一直未能想明白,本文尝试结合jdk,openjdk6的部分源码分析弱引用实现的原理,供大家参考,部分技术细节没有仔细研究,如有疑问欢迎留言讨论

实例分析

我们以WeakHashMap的处理过程为例介绍一个weak reference的生命周期,首先我们调用WeakHashMap的put方法放入对象到Map中,WeakHashMap的Entry继承了WeakReference

下面是put的部分代码

注意new Entry传递了一个reference queue到构造函数中,此构造函数最终会调用Reference的构造函数

referent是我们之前传入的hashmap的key对象,queue的作用是用来读取referent被回收的weak reference,生产者是谁后续介绍,此时WeakHashMap中已经存在了一个对象,先将key对象的strong ref制空并尝试触发gc,比如使用System.gc()来显式的触发gc,然后调用WeakHashMap的size方法返回集合的个数,绝大多数情况下会是0,这个过程中发生了什么呢?

第一步,key没有可达的strong ref,美国服务器,仅仅存在一个weak reference的referent变量仍然指向了key,触发GC时,以openjdk6的parNew为例,jvm在young generation gc时会尝试获取Reference对象里的静态全局锁

在openjdk6里的部分源代码,完整代码请参考instanceRefKlass.cpp文件

此处代码在parNew gc时执行,目的就是尝试获取全局锁,在gc完成后,jvm会将key被回收的weak reference组成一个queue并赋值到Reference的pending属性然后释放锁,香港服务器,参考方法:

在一次gc后,Reference对象的pending属性不再为空,香港虚拟主机,让我们看看Reference的部分代码

首先是pending属性的说明:

接下来是Reference中的内部类ReferenceHandler,它继承了Thread,看看run方法的代码

一旦jvm notify了前面提到的锁,这个线程就被激活并开始执行,作用是将之前jvm赋值过来的pending对象中的WeakReference对象enqueue到指定的队列中,比如WeakHashMap内部定义的ReferenceQueue属性

此时map的queue中保存了referent已经被回收的WeakReference队列,也就是map的Entry对象,当调用size方法时,内部首先调用expungStaleEntries方法清除被回收掉的Entry,代码如下

ok,就这样map的废弃Entry被clear,size返回为0

经过简单的测试程序发现:

一次gc未必能完全回收所有的weak ref

weak对象也可能会出现在old generation

参考:

本文出自 “RockyBalboa” 博客,请务必保留此出处

然后拍一些美得想哭的照片,留给老年的自己。

weakreference实现原理分析

相关文章:

你感兴趣的文章:

标签云: