强引用 -> 软引用 -> 弱引用 -> 虚引用

强引用

只要某个对象有强引用与之关联,JVM必定不会回收这个对象,即使在内存不足的情况下,JVM宁愿抛出OutOfMemory错误也不会回收这种对象

使用场景
  1. Object obj = new Object();

如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象

软引用

软引用是用来描述一些有用但并不是必需的对象,只有在内存不足的时候JVM才会回收该对象

使用场景
  1. SoftReference<String> sr = new SoftReference<String>(new String("hello"));
  2. System.out.println(sr.get());
  • 解决OOM的问题
  • 实现缓存

SoftReference 除了 SoftReference(T referent) 构造方法外,还有一个SoftReference(T referent, ReferenceQueue<? super T> q),软引用和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中,作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性

  1. private void test() {
  2. // 制造OOM
  3. ArrayList<Byte[]> list = new ArrayList<>();
  4. // 引用队列
  5. ReferenceQueue<Byte[]> referenceQueue = new ReferenceQueue<>();
  6. SoftReference<Byte[]> softReference = new SoftReference<>(new Byte[100000], referenceQueue);
  7. // 软引用对象
  8. System.out.println(softReference);
  9. while (true) {
  10. list.add(new Byte[100000]);
  11. if (softReference.get() == null) {
  12. System.out.println("软引用被回收");
  13. SoftReference reference = (SoftReference) referenceQueue.poll();
  14. System.out.println(reference);
  15. }
  16. }
  17. }

输出结果为:

  1. java.lang.ref.SoftReference@61bbe9ba
  2. 软引用被回收
  3. java.lang.ref.SoftReference@61bbe9ba
  4. Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

当这个SoftReference所软引用的Object被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收,同时也可以把这些失去所软引用的对象的SoftReference对象清除掉

弱引用

弱引用和软引用不同,每次GC时,JVM都会回收这一部分对象,弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

使用场景
  • WeakHashMap
  • ThreadLocal

弱引用和软引用类似,同样可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

  1. private void test() {
  2. // 用于触发GC
  3. ArrayList<Byte[]> list = new ArrayList<>();
  4. // 引用队列
  5. ReferenceQueue<Byte[]> referenceQueue = new ReferenceQueue<>();
  6. WeakReference<Byte[]> weakReference = new WeakReference<>(new Byte[100000], referenceQueue);
  7. // 弱引用对象
  8. System.out.println(weakReference);
  9. while (true) {
  10. list.add(new Byte[100000]);
  11. if (weakReference.get() == null) {
  12. System.out.println("弱引用被回收");
  13. WeakReference reference = (WeakReference) referenceQueue.poll();
  14. System.out.println(reference);
  15. break;
  16. }
  17. }
  18. }

输出结果:

  1. java.lang.ref.WeakReference@61bbe9ba
  2. 弱引用被回收
  3. java.lang.ref.WeakReference@61bbe9ba

虚引用

虚引用(PhantomReference)顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

使用场景

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用(只有一个构造方法:PhantomReference(T referent, ReferenceQueue<? super T> q)),虚引用的get方法始终返回null。

当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。