文章目录
Java引用类型原理
引用类型
JVM将引用类型分为以下4中:
- 强引用(FinalReference)
- 软引用(SoftReference )
- 弱引用(WeakReference )
- 虚引用(PhantomReference )
Reference
Reference类是Java.lang.ref包里的一个抽象类
public abstract class Reference<T> {
//引用的对象
private T referent;
//回收队列,由使用者在Reference的构造函数中指定
volatile ReferenceQueue<? super T> queue;
//当该引用被加入到queue中的时候,该字段被设置为queue中的下一个元素,以形成链表结构
volatile Reference next;
//在GC时,JVM底层会维护一个叫DiscoveredList的链表,存放的是Reference对象,discovered字段指向的就是链表中的下一个元素,由JVM设置
transient private Reference<T> discovered;
//进行线程同步的锁对象
static private class Lock { }
private static Lock lock = new Lock();
//等待加入queue的Reference对象,在GC时由JVM设置,会有一个java层的线程(ReferenceHandler)源源不断的从pending中提取元素加入到queue
private static Reference<Object> pending = null;
}
强引用(FinalReference)
强引用是指创建一个对象并它赋值给一个引用,引用是存在JVM中的栈(还有方法区)中的。具有强引用的对象,垃圾回收器绝对不会去回收它,直到内存不足以分配时,抛出OOM。大多数情况,我们new一个对象,并把它赋值给一个变量,这个变量就是强引用。
Object obj = new Object();
软引用(SoftReference)
软引用描述一些还有用但非必需的对象,具有软引用关联的对象,内存空间足够时,垃圾回收器不会回收它。当内存不足时(接近OOM),垃圾回收器才会去决定是否回收它。
Object obj = new Object();
SoftReference<Object> softRef = new SoftReference(obj);
// 使用 softRef.get() 获取软引用所引用的对象
Object objg = softRef.get();
软引用实现内存缓存
弱引用(WeakReference )
弱引用描述非必需对象,但它的强度比软引用更弱一些。WeakReference对其引用的对象并无保护作用,当垃圾回收器进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。弱引用一般用于实现canonicalizing mappings (正规化映射),典型的应用是WeakHashMap。
Object obj = new Object();
ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
虚引用(PhantomReference )
虚引用也被称为幽灵引用或幻引用,它是最弱的一种引用关系。虚引用并不会影响对象的GC,而且并不可以通过PhantomReference对象取得一个引用的对象。虚引用唯一的作用则是利用其必须和ReferenceQueue关联使用的特性,当其绑定的对象被GC回收后会被推入ReferenceQueue,外部程序可以通过对此队列轮询来获得一个通知,以完成一些目标对象被GC后的清理工作。
PhantomReference 的构造方法,与SoftReference和WeakReference不同,他的构造必须传入一个ReferenceQueue
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q)
;}
严格的说,虚引用是会影响对象生命周期的,如果不做任何处理,只要虚引用不被回收,那其引用的对象永远不会被回收。所以一般来说,从ReferenceQueue中获得PhantomReference对象后,如果PhantomReference对象不会被回收的话(比如被其他GC ROOT可达的对象引用),需要调用clear方法解除PhantomReference和其引用对象的引用关系。
DirectByteBuffer中是用虚引用的子类Cleaner.java来实现堆外内存回收的,后续会写篇文章来说说堆外内存的里里外外。