1、Reference对象和被引用的对象
首先需要理解Reference对象和被引用的对象的区分。 Object obj =new Object();Reference<Object> objRef = new SoftReference(obj);
被引用的对象指的是obj这个对象,Reference对象指的是objRef。
Java中的三种常见Reference类型:SoftReference、WeakReference和PhantomReference中有关GC的说明,针对的都是被引用的对象。
SoftReference:内存不足时,回收被引用的对象。jvm保证在内存溢出之前已经回收了被SoftReference引用的对象的空间。
WeakReference:正常GC时就可以回收,是否回收无法保证
PhantomReference:比上面两种还要弱的引用,所以应该也是正常GC时就可以回收,何时回收无法保证。
注意这里回收的都是这个被引用的对象,而不是Reference对象本身。实际上Reference对象本身是作为一个强引用而存在的(个人理解)。 所以实际的效果就是,被引用的对象被回收,但我们仍然可以获取Reference对象。
2、Reference和ReferenceQueue
其实每个Reference对象都有一个对应的ReferenceQueue,用来存储Reference对象。一个ReferenceQueue对象可以被多个Reference共享。
关于ReferenceQueue的作用,Oracle的官方文档上给出的描述如下
“ Reference queues, to which registered reference objects are appended by the garbage collector after the appropriate reachability changes are detected. ”
当被引用的对象被GC回收之后,GC会把Reference对象添加到队列中。因此,可以这样理解,在队列中的Reference对象,它们引用的对象被GC回收。而不在队列中的,它们引用的对象则还没有被GC回收。这个队列的存在,可以帮助开发者执行一些与被引用对象相关联的数据清理的动作。
比如说有一个文件对象,我们想在这个文件对象被GC回收之后,同时将这个文件从磁盘上删除。这样就可以从ReferenceQueue来获取那些引用的文件被GC回收了的Reference对象,并进行文件的清理动作 --- 这就是tomcat的FileCleaningTracker的实现原理。
3、Reference的生命周期
如果一个Reference在创建的时候,有指定了正常可用的ReferenceQueue,那么这个Reference对象便会经历4个生命周期
Active --> Pending --> Enqueued --> Inactive
Active状态下被引用的对像还没有被GC回收
Pending 被引用的对象被GC回收后,如果Reference对象创建的时候有指定ReferenceQueue,就进入Pending状态,等待被放入ReferenceQueue中
Enqueued 进入了ReferenceQueue队列
Inactive 从ReferenceQueue中被取出
如果在创建ReferenceQueue的时候没有指定队列,这个Reference就会使用默认的ReferenceQueue.Null队列,生命周期直接由 Active 进入 Inactive
ps:Reference内部有一个pending队列,GC只是把对象添加到这个队列中。Reference有一个后台线程去从pending队列中取出Reference对象,添加到ReferenceQueue中。
4、GC和进入ReferenceQueue的顺序
(这部分内容来自大神Ethan Nicholas的博客)
在简单的模型中,进入了ReferenceQueue的Reference对象所引用的目标对象已经被回收,但实际上对于WeakReference和PhantomReference之间还是存在一定的差别,主要在于,进入队列和GC操作的先后顺序。在这一点上,SoftReference和WeakReference是相同的
对于WeakReference来说,进入ReferenceQueue是在目标对象真正被GC之前,所以这个时候有可能通过重写finalize()方法来重新获得目标对象
对于PhantomReference来说,当目标对象被真正GC回收之后,才会进入到ReferenceQueue中,根本无法重新获得目标对象
5、Reference扩展
除了直接使用jdk提供的三种Reference之外,开发人员还可以通过继承SoftReference、WeakReference或PhantomReference来添加自定义的功能,但不能够直接继承Reference。
下面是一篇关于Reference的使用的文章
http://java.dzone.com/articles/finalization-and-phantom
来自大神Ethan Nicholas的博客文章 ---- 内容很全面
https://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html