java中的引用分为4种,分别是:1.强引用;2.软引用;3.弱引用;4.虚引用。四种引用分别有各自的特点,下面分别通过代码对四种类型的引用进行一下测试。
1.强引用
强引用是我们平时最常用的一种引用类型。在对象被引用的时候,不会被gc的垃圾回收器回收。当没有引用时,堆中对象会被回收。
示范代码:
1 /** 2 * 验证垃圾回收机制类 3 * @author 4 * 5 */ 6 public class M { 7 // 重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。 8 // 平时开发不建议在该位置写代码,容易导致OOM问题 9 @Override 10 protected void finalize() { 11 System.out.println("finalize"); 12 } 13 }
1 import java.io.IOException; 2 /** 3 * 强引用 普通的引用 4 * 5 * 栈里的小m指向堆里的M对象,这个引用叫做强引用,只有没有任何引用指向对象的时候,对象才会被垃圾回收器回收 6 * @author Lys 7 * 8 */ 9 public class T01_NormalReference { 10 public static void main(String[] args) throws IOException { 11 M m = new M(); 12 m=null; 13 System.gc(); 14 15 System.in.read(); 16 } 17 }
运行结果:
finalize // 说明引用在被置为null 后,在系统gc的时候,对象被垃圾回收器回收了
2.软引用
只被软引用所引用的对象,会在jvm内存不够用的时候,被垃圾回收器回收。通过下面的测试代码我们可以看出:在m刚被定义的时候,这个时候m还是可以get到值的,然后调用系统gc,m对象也没有被垃圾回收器回收。但是当定义其他对象使内存不够用的时候,该对象就被回收掉了。该引用适用场景:一个比较大的缓存对象,经常需要读取。当系统空间足够的时候,就将其缓存在jvm中,当可用空间不足的时候,就将其回收掉。
示范代码:
1 /** 2 * 软引用 3 * 4 * 软应用内的对象会随着空间不够用而消失,一般应用于缓存。 5 * @author Lys 6 * 7 */ 8 public class T02SoftReference { 9 public static void main(String[] args) { 10 SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]); 11 12 System.out.println(m.get()); 13 System.gc(); 14 try { 15 Thread.sleep(500); 16 } catch (Exception e) { 17 e.printStackTrace(); 18 } 19 System.out.println(m.get()); 20 byte[] b = new byte[1024*1024*3]; 21 byte[] b1 = new byte[1024*1024*3]; 22 System.out.println(m.get()); 23 } 24 }
代码执行参数:-Xmx20M
代码执行结果:
[B@15db9742 [B@15db9742 null // 前两个打印输出证明在内存足够的情况下不会被回收,第三个输出表示,当内存不足时,软引用的对象就被垃圾回收器回收了
3.弱引用
只有弱引用引用的对象在遇到垃圾回收器执行垃圾回收的时候,就会被回收。弱引用的应用场景:ThreadLocal 对象在调用set方法,在存储对象的时候。本身将当前线程局部变量对象作为key值,存入线程的ThreadLocalMap中,被set的值作为ThreadLocalMap的value。jdk源代码如下:
static class ThreadLocalMap { /** * The entries in this hash map extend WeakReference, using * its main ref field as the key (which is always a * ThreadLocal object). Note that null keys (i.e. entry.get() * == null) mean that the key is no longer referenced, so the * entry can be expunged from table. Such entries are referred to * as "stale entries" in the code that follows. */ static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
这里的super(key)创建了一个弱引用,当ThreadLocal 对象在栈中的引用消失后,这个对象就会被垃圾回收器回收,而不必担心出现内存泄漏问题。
示范代码:
/** * 验证垃圾回收机制的对象 * @author * */ public class M { // 重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。 // 平时开发不建议在该位置写代码,容易导致OOM问题 @Override protected void finalize() { System.out.println("finalize"); } }
import java.lang.ref.WeakReference; import java.util.WeakHashMap; /** * 弱引用 垃圾回收器看到后就回收 ,,就会被回收 * 应用场景:ThreadLocal 解决内存泄漏问题 ,但是用户自己创建的value还存在,所以tl中创建的内容,在tl不用以后,要进行remove操作。 * @author Lys * */ public class T03_WeakRefernce { public static void main(String[] args) { WeakReference<M> m = new WeakReference<M>(new M()); System.out.println(m.get()); System.gc(); System.out.println(m.get()); // ThreadLocal<M> tl = new ThreadLocal<>(); // tl.set(new M()); // tl.remove(); } }
代码执行结果:
reference.M@15db9742 null finalize
4.虚引用
虚引用在jvm 中没有内存,用于管理在虚拟机之外的内存。如下图所示,虚引用必须当我们的虚拟机需要管理一块不存在于jvm的内存时,需要跟踪对象的垃圾回收状态,如果对象被回收了,那么将该对象的引用放入queue,根据queue中取出的对象去将对应的JVM外面的内存进行操作。
示范代码:
1 /** 2 * 虚引用 get不到,随时被回收的对象 3 * 4 * 作用:管理堆外内存NIO 5 * @author Lys 6 * 7 */ 8 9 import java.lang.ref.PhantomReference; 10 import java.lang.ref.Reference; 11 import java.lang.ref.ReferenceQueue; 12 import java.util.LinkedList; 13 import java.util.List; 14 15 public class T04_phantomReference { 16 private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>(); 17 public static void main(String[] args) { 18 PhantomReference<M> phantomReference = new PhantomReference<M>(new M(),QUEUE ); 19 20 new Thread(()->{ 21 22 try { 23 System.gc(); 24 Thread.sleep(1000); 25 } catch (Exception e) { 26 e.printStackTrace(); 27 Thread.currentThread().interrupt(); 28 } 29 System.out.println(phantomReference.get()); 30 System.gc(); 31 32 }).start(); 33 34 new Thread(()->{ 35 while (true) { 36 Reference<? extends M> poll = QUEUE.poll(); 37 if (poll!=null) { 38 39 System.out.println("----- 虚引用对象被jvm回收-------"+poll); 40 } 41 } 42 }).start(); 43 } 44 }
执行结果:
finalize null ----- 虚引用对象被jvm回收-------java.lang.ref.PhantomReference@4a140fe5