前言
了不起最近在整理一些面试资料,发现对于强、软、弱、虚引用的资料少之又少,所以决定整理一下关于这方面的资料,方便金三银四跳槽。
强引用
特点
强引用是较为普遍的一种引用,在我们编写Java代码时,绝大多数的引用,使用的都是强引用。当一个对象使用的是强引用时,JVM垃圾回收器不会回收该对象,即使内存不足,JVM宁愿抛出OOM异常,也不会主动去回收该对象。
代码示例
public class StrongReference { public static void main(String[] args) { MyObject myObject = new MyObject(); System.gc(); System.out.println("第一次gc,myObject = " + myObject); // 手动置为Null,并通知JVM进行垃圾回收 myObject = null; System.gc(); System.out.println("第二次gc,myObject = " + myObject); } } class MyObject{ @Override protected void finalize() throws Throwable { System.out.println("execute finalize method..."); } } // 执行结果: // 第一次gc,myObject = ref.MyObject@1b6d3586 // 第二次gc,myObject = null // execute finalize method...
软引用
特点
软引用是一种较强的引用类型,当内存足够时,JVM不会回收软引用的对象,当内存不足时,JVM会回收软引用的对象。
代码示例
前置条件:调整JVM参数,将最大内存调整为10MB。-Xms10m -Xmx10m
import java.lang.ref.SoftReference; import java.util.concurrent.TimeUnit; public class SoftReferenceExample { public static void main(String[] args) { SoftReference softReference = new SoftReference<MyObject>(new MyObject()); System.out.println("gc before, softReference = " + softReference.get()); System.gc(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("gc after, softReference = " + softReference.get()); try { // 创建20MB的字节数组 byte[] bytes = new byte[20 * 1024 * 1024]; } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("memory not enough, softReference = " + softReference.get()); } } } // 执行结果: // gc before, softReference = ref.MyObject@1b6d3586 // gc after, softReference = ref.MyObject@1b6d3586 // Exception in thread "main" java.lang.OutOfMemoryError: Java heap space // at ref.SoftReferenceExample.main(SoftReferenceExample.java:22) // memory not enough, softReference = null // execute finalize method...
弱引用
特点
弱引用是一种比软引用更弱的引用类型,无论内存是否充足,JVM垃圾回收器都会立即回收弱引用对象。
代码示例
import java.lang.ref.WeakReference; import java.util.concurrent.TimeUnit; public class WeakReferenceExample { public static void main(String[] args) { WeakReference weakReference = new WeakReference<>(new MyObject()); System.out.println("gc before, softReference = " + weakReference.get()); System.gc(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("gc after, softReference = " + weakReference.get()); } } // 执行结果: // gc before, softReference = ref.MyObject@1b6d3586 // execute finalize method... // gc after, softReference = null
虚引用
特点
虚引用是最弱的引用类型,主要用于跟踪对象是否被垃圾回收器回收。同时,虚引用必须与一个引用队列一同使用。当JVM准备回收一个对象时,如果发现它是虚引用,那么会将这个虚引用加入到与之关联的一个引用队列中。
代码示例
import java.lang.ref.PhantomReference; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; public class PhamtonReferenceExample { public static void main(String[] args) throws InterruptedException { ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>(); PhantomReference<MyObject> phantomReference = new PhantomReference<>(new MyObject(), referenceQueue); List<byte[]> list = new ArrayList<>(); new Thread(() -> { while (true) { list.add(new byte[2 * 1024 * 1024]); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(phantomReference.get() + "\t" + "list add success!!!"); } }).start(); new Thread(() -> { while (true) { Reference<? extends MyObject> ref = referenceQueue.poll(); if (ref != null) { System.out.println("虚对象回收加入了对列"); break; } } }).start(); } } // 执行结果: // execute finalize method... // null list add success!!! // null list add success!!! // null list add success!!! // Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space // at ref.PhamtonReferenceExample.lambda$main$0(PhamtonReferenceExample.java:21) // at ref.PhamtonReferenceExample$$Lambda$1/1324119927.run(Unknown Source) // at java.lang.Thread.run(Thread.java:748) // 虚对象回收加入了对列
总结
引用类型可用于灵活管理对象的生命周期,且在Java源码中有较多的应用场景,如ThreadLocal使用的就是弱引用。希望本文能够帮助小伙伴们对Java的四种引用类型有更深入的了解。