类层次结构
所有引用类型都是java.lang.ref.Reference的子类,它提供了get()方法。除了幻象引用,如果对象还没有被销毁,都可以通过get方法获取原有对象。这意味着,利用软引用和弱引用,我们都可以访问到对象,重新指向强引用,也就是人为的改变了对象的可达性状态。所以,对于软引用和弱引用之类,垃圾收集器可能会存在二次确认的问题,以保证处于弱引用状态的对象没有变为强引用。
我们知道在Java中除了基础的数据类型以外,其它的都为引用类型。而Java根据其生命周期的长短将引用类型又分为强引用、软引用、弱引用、幻象引用 。正常情况下我们平时基本上我们只用到强引用类型,而其他的引用类型我们也就在面试中,或者平日阅读类库或其他框架源码的时候才能见到。
1.强引用
我们平日里面的用到的new了一个对象就是强引用,例如 Object obj = new Object(); :::info 当JVM的内存空间不足时,宁愿抛出OutOfMemoryError使得程序异常终止也不愿意回收具有强引用的存活着的对象。 ::: 当一个普通对象没有其他引用关系,只要超过了引用的作用域或者显式地将引用赋值为null时,对象就不是存活着,这样就会可以被GC回收了。当然回收的时间是不一定的,具体得看GC回收策略。
// 强引用
String strongReference = new String("abc");
2.软引用
软引用的生命周期比强引用短一些。软引用是通过SoftReference类实现的。
// 软引用
String str = new String("abc");
SoftReference<String> softReference = new SoftReference<String>(str);
这样就是一个简单的软引用使用方法。通过get()方法获取对象。
:::info 当JVM认为内存空间不足时,就回去试图回收软引用指向的对象,也就是说在JVM抛出OutOfMemoryError之前,会去清理软引用对象。 :::
软引用可以与引用队列(ReferenceQueue)联合使用:
当softObj软引用的obj被GC回收之后,softObj 对象就会被塞到queue中,之后我们可以通过这个队列的poll()来检查你关心的对象是否被回收了,如果队列为空,就返回一个null。反之就返回软引用对象也就是softObj。
软引用一般用来实现内存敏感的缓存,如果有空闲内存就可以保留缓存,当内存不足时就清理掉,这样就保证使用缓存的同时不会耗尽内存。例如图片缓存框架中缓存图片就是通过软引用的。
3.弱引用
弱引用是通过WeakReference类实现的,它的生命周期比软引用还要短,也是通过get()方法获取对象。
Object obj = new Object();
WeakReference<Object> weakReference = new WeakReference<Object>(obj);
obj = null;
System.gc();
System.out.println(weakReference.get());// 有时候会返回Null
System.out.println(weakReference.isEnqueued());//判断是否有垃圾回收标记,表示即将回收的垃圾
在GC的时候,不管内存空间足不足都会回收这个对象,同样也可以配合ReferenceQueue 使用,也同样适用于内存敏感的缓存。ThreadLocal中的key就用到了弱引用。
4.幻象引用
也称虚引用,是通过PhantomReference类实现的。任何时候可能被GC回收。
// 虚引用
Object obj = new Object();
ReferenceQueue refQueue = new ReferenceQueue();
PhantomReference<Object> phantomReference = new PhantomReference<Object>(obj, refQueue);
System.out.println(phantomReference.get()); // 永远返回Null
System.out.println(phantomReference.isEnqueued()); //返回时否从队列中删除
无法通过虚引用访问对象的任何属性或者函数(get方法返回null)。
虚引用是必须配合ReferenceQueue 使用的,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。