最近在看netty的一些源码,看到了FastThreadLocal,里面使用了弱引用来跟踪JVM的垃圾回收,故总结一下java中的四种引用类型,以及使用场景。
java中的引用类型
java中有四种引用类型,分别是强引用,软引用,弱引用,虚引用。
强引用
强引用是平时对象引用的方式,例如 A a = new A(); 申明一个变量引用一个对象。
Reference 类
其他几种引用都继承了Reference 类型,所以先介绍Reference类

对象可达性
垃圾回收判断对象是否可回收使用的是可达性算法来判断对象是否还存在引用。
可达性判断原则
1.存在多条引用路径,以最强的引用为准
2.存在一条引用路径,以最弱的引用为准
Reference类的作用:
实现特定类型的引用
用户可以通过Reference类关联的ReferenceQueue得知对象被回收
Reference 类中的属性
private T referent; /* Treated specially by GC */
volatile ReferenceQueue<? super T> queue;
Reference next;
transient private Reference<T> discovered; /* used by VM */
private static Reference<Object> pending = null;
referent 表示引用的对象
queue:引用队列,有入队、出队功能。队列中的引用对象由垃圾回收器回收的时候追加到队列中。
next ,discovered,pending 这几个属性下面再介绍。
Reference 对象的状态
Reference对象有4种状态
1.Active
新创建的Reference实例的状态。当垃圾回收器发现Reference实例引用的对象referent不可达时,垃圾回收器修改该Reference实例的状态为Pending或者Inactive.如果Reference实例在创建的时候传入了ReferenceQueue 则状态变成Pending.
2.Pending
pending-Reference 列表中Reference实例的状态,这些Reference实例等待被加入ReferenceQueue。
next 指向Reference自己
当垃圾回收器将Reference对象加入到pending-Reference 列表时,ReferenceHandler线程将它从pending-Reference移除,加入到ReferenceQueue中,下一个pending Reference通过discovered属性来关联
3.Enqueued
ReferenceQueue中的Reference实例状态。如果Reference从队列中移除变成Inactive状态。
Enqueued 的Reference指向特定的Reference Queue ‘ENQUEUED’,next指向queue中的成员或者自身(如果当前reference是queue中的尾节点)
4.Inactive
Reference实例的最终状态。
queue指向 NULL ReferenceQueue,next 指向自身
Reference对象状态变更
如果Reference对象关联了ReferenceQueue,Reference 引用的对象被回收时Reference对象会先加入到pending-Reference列表.这里没有直接由JVM将Reference对象加入到ReferenceQueue,而是用了一个pending-Reference存放Reference对象,然后由一个ReferenceHandler 线程不断的轮询pending-Reference,通过调用ReferenceQueue(就是Reference对象中的queue对象)的enqueue方法将Reference对象加入这个ReferenceQueue。
上面提到的Reference类中的next属性 表示下个Reference对象。pending表示pending-Reference的头结点,discovered 由JVM使用,表示pending-Reference的下个节点。
SoftReference
一个对象存在根对象对其有直接或者间接SoftReference,没有其他强引用路径,称为 softly reachable对象。JVM 在抛出OutOfMemory异常之前一定会对softly reachable对象进行回收。
JVM不仅仅只会考虑当前内存情况,还会考虑软引用所指向的referent最近使用情况和创建时间来综合决定是否回收该referent
WeakReference
一个对象如果被 WeakReference 引用,没有其他强引用,只要发生GC 就会被清理
Phantom reference
Phantom reference 可以用在对象被回收的时候做一些资源释放的场景,代替finalization机制。当垃圾回收器判断一个对象是phantom reachable 状态时,会将该对象的Phantom reference对象加入ReferenceQueue.用户可以通过额外的线程尝试将该refernce 从ReferenceQueue中移除,然后执行一些资源释放操作(相当于通过ReferenceQueue接受对象被回收的通知)。Phantom reference 在使用时一定要关联一个ReferenceQueue。
不像软引用和弱引用,垃圾回收器不会自动回收Phantom reference对象,程序必须自己清除Phantom reference.
FinalReference
JVM虚拟机使用,在对象被回收前可以执行finalize方法。一个对象重写了Object类的finalize 方法,方法体不为空就被FinalReference引用,回收时会加入相关ReferenceQueue,系统会启动一个FinalizerThread线程取出ReferenceQueue中的对象,调用finalize方法。
参考文章:
Java Reference详解
Internals Of Java Reference Object
jdk源码阅读-Reference