Java中支持四种引用类型。平时我们可能只用到其中一种,但对各种引用类型都有一定了解是有必要的。
本文针对四种引用类型的含义特征、应用场景、使用方式进行分析。
强引用
含义特征
强引用(Strong Reference)
当我们使用new创建对象时,被创建的对象就是强引用。
例如Object object = new Object(),其中的object就是一个强引用了。
如果一个对象具有强引用,JVM在垃圾回收时就不会去回收它(GC它)。JVM宁可会报OOM(OutofMemoryError)来终止程序,也不回收该对象。
如果对JVM垃圾回收不太了解,传送门:(之后补上)
如果对OOM不太了解,传送门:(什么是OOM?)
应用场景
我们平时开发中用到的new命令就是在创建强引用,应用场景不言而喻~
使用方式
Object object = new Object();
软引用
含义特征
软引用(Soft Reference)
如果一个对象只具备软引用,如果内存空间足够,那么JVM就不会GC它,如果内存空间不足了,就会GC该对象。
应用场景
可以用来实现缓存。一般缓存是用来加速访问的,但如果服务器有产生OOM的风险,就应该把缓存GC掉。
使用方式
SoftReference<Object> softReference = new SoftReference(new Object());
softReference.get();//获取被软引用的对象
弱引用
含义特征
弱引用(Weak Reference)
如果一个对象只具有弱引用,只要JVM的GC线程检测到了,就会立即回收。
弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉弱引用的内存。
应用场景
ThreadLocal就使用了弱引用,解决了当没有强引用指向 ThreadLocal 变量时,ThreadLocal 不能被回收而造成的内存泄漏的问题。
传送门:(ThreadLocal深入解析)
使用方式
WeakReference<Object> weakReference = new WeakReference(new Object());
weakReference.get();//获取被弱引用的对象
虚引用
含义特征
虚引用(Phantom Reference)
如果一个对象只具有虚引用,那么它就和没有任何引用一样,随时会被JVM当作垃圾进行GC。 建立虚引用只是在被回收时发一个通知。无法通过虚引用来取得一个对象实例。
应用场景
有了虚引用的“通知机制”,我们就可以在所引用的对象的内存被回收之前采取必要的行动。
举个具体的例子:
jdk中直接内存的回收就用到虚引用。由于jvm自动内存管理的范围是堆内存,而直接内存是在堆内存之外,Java会在堆内存分配一个对象保存这个堆外内存的引用,这个对象被垃圾收集器管理,一旦这个对象被回收,相应的用户线程会收到通知并对直接内存进行清理工作。
这里补充一个tip:
直接内存:它不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。它是一种堆外内存,通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。
如果对虚拟机运行时数据区不太了解,传送门:(JVM运行时数据区)
使用方式
虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference(new Object(),queue);
phantomReference.get();//获取被虚引用的对象。它一定返回null值,因为无法通过虚引用来取得一个对象实例