java中的引用分为4种,分别是:1.强引用;2.软引用;3.弱引用;4.虚引用。四种引用分别有各自的特点,下面分别通过代码对四种类型的引用进行一下测试。
1.强引用
强引用是我们平时最常用的一种引用类型。在对象被引用的时候,不会被gc的垃圾回收器回收。当没有引用时,堆中对象会被回收。
示范代码:
1 /**
2 * 验证垃圾回收机制类3 *@author
4 *5 */
6 public classM {7 //重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。8 //平时开发不建议在该位置写代码,容易导致OOM问题
9 @Override10 protected voidfinalize() {11 System.out.println("finalize");12 }13 }
验证类
1 importjava.io.IOException;2 /**
3 * 强引用 普通的引用4 *5 * 栈里的小m指向堆里的M对象,这个引用叫做强引用,只有没有任何引用指向对象的时候,对象才会被垃圾回收器回收6 *@authorLys7 *8 */
9 public classT01_NormalReference {10 public static void main(String[] args) throwsIOException {11 M m = newM();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 *@authorLys6 *7 */
8 public classT02SoftReference {9 public static voidmain(String[] args) {10 SoftReference 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@15db9742null
//前两个打印输出证明在内存足够的情况下不会被回收,第三个输出表示,当内存不足时,软引用的对象就被垃圾回收器回收了
3.弱引用
只有弱引用引用的对象在遇到垃圾回收器执行垃圾回收的时候,就会被回收。弱引用的应用场景:ThreadLocal 对象在调用set方法,在存储对象的时候。本身将当前线程局部变量对象作为key值,存入线程的ThreadLocalMap中,被set的值作为ThreadLocalMap的value。jdk源代码如下:
static classThreadLocalMap {/*** 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>{/**The value associated with this ThreadLocal.*/Object value;
Entry(ThreadLocal>k, Object v) {super(k);
value=v;
}
}
这里的super(key)创建了一个弱引用,当ThreadLocal 对象在栈中的引用消失后,这个对象就会被垃圾回收器回收,而不必担心出现内存泄漏问题。
示范代码:
/*** 验证垃圾回收机制的对象
*@author**/
public classM {//重写finalize 方法,该方法是Object对象的方法,在对象被回收时执行。//平时开发不建议在该位置写代码,容易导致OOM问题
@Overrideprotected voidfinalize() {
System.out.println("finalize");
}
}
验证对象
importjava.lang.ref.WeakReference;importjava.util.WeakHashMap;/*** 弱引用 垃圾回收器看到后就回收 ,,就会被回收
* 应用场景:ThreadLocal 解决内存泄漏问题 ,但是用户自己创建的value还存在,所以tl中创建的内容,在tl不用以后,要进行remove操作。
*@authorLys
**/
public classT03_WeakRefernce {public static voidmain(String[] args) {
WeakReference m = new WeakReference(newM());
System.out.println(m.get());
System.gc();
System.out.println(m.get());//ThreadLocal tl = new ThreadLocal<>();//tl.set(new M());//tl.remove();
}
}
代码执行结果:
reference.M@15db9742nullfinalize
4.虚引用
虚引用在jvm 中没有内存,用于管理在虚拟机之外的内存。如下图所示,虚引用必须当我们的虚拟机需要管理一块不存在于jvm的内存时,需要跟踪对象的垃圾回收状态,如果对象被回收了,那么将该对象的引用放入queue,根据queue中取出的对象去将对应的JVM外面的内存进行操作。
示范代码:
1 /**
2 * 虚引用 get不到,随时被回收的对象3 *4 * 作用:管理堆外内存NIO5 *@authorLys6 *7 */
8
9 importjava.lang.ref.PhantomReference;10 importjava.lang.ref.Reference;11 importjava.lang.ref.ReferenceQueue;12 importjava.util.LinkedList;13 importjava.util.List;14
15 public classT04_phantomReference {16 private static final ReferenceQueue QUEUE = new ReferenceQueue<>();17 public static voidmain(String[] args) {18 PhantomReference phantomReference = new PhantomReference(newM(),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 }
执行结果:
finalizenull
----- 虚引用对象被jvm回收-------java.lang.ref.PhantomReference@4a140fe5