無(wú)論是通過(guò)引用計(jì)數(shù)算法判斷對(duì)象的引用數(shù)量,還是通過(guò)可達(dá)性分析算法判斷對(duì)象是否引用鏈可達(dá),判定對(duì)象是否存活都和“引用”離不開(kāi)關(guān)系。
在JDK 1.2版之后,Java對(duì)引用的概念進(jìn)行了擴(kuò)充,將引用分為強(qiáng)引用(Strongly Re-ference)、軟引用(Soft Reference)、弱引用(Weak Reference)和虛引用(Phantom Reference)4種,這4種引用強(qiáng)度依次逐漸減弱。
一、強(qiáng)引用
強(qiáng)引用是最傳統(tǒng)的“引用”的定義,是指在程序代碼之中普遍存在的引用賦值,即類似“Object obj=new Object()”這種引用關(guān)系。無(wú)論任何情況下,只要強(qiáng)引用關(guān)系還存在,垃圾收集器就永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
二、軟引用
軟引用是用來(lái)描述一些還有用,但非必須的對(duì)象。只被軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常前,會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收,如果這次回收還沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。在JDK 1.2版之后提供了SoftReference類來(lái)實(shí)現(xiàn)軟引用。
應(yīng)用場(chǎng)景:緩存。
import java.lang.ref.SoftReference;
/**
* @description: 軟引用
* ·軟引用是用來(lái)描述一些還有用,但非必須的對(duì)象。只被軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)
* 存溢出異常前,會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收,如果這次回收還沒(méi)有足夠的內(nèi)存,
* 才會(huì)拋出內(nèi)存溢出異常。在JDK 1.2版之后提供了SoftReference類來(lái)實(shí)現(xiàn)軟引用。
*
* 應(yīng)用場(chǎng)景:緩存
*
* @author:weirx
* @date:2021/5/19 16:39
* @version:3.0
*/
public class SoftReferenceTest {
public static void main(String[] args) throws InterruptedException {
SoftReference<byte[]> m = new SoftReference(new byte[1024 * 1024 * 10]);
System.out.println(m.get());
//第一次垃圾回收
System.gc();
Thread.sleep(1000);
System.out.println(m.get());
//分配一個(gè)強(qiáng)引用的byte,看看當(dāng)堆空間不足時(shí),是否會(huì)將軟引用回收。
// 需要啟動(dòng)時(shí)將最大堆內(nèi)存設(shè)置為25M,當(dāng)內(nèi)存不足后發(fā)生第二次垃圾回收之后在獲取軟引用就是null。
byte[] bytes = new byte[1024 * 1024 * 12];
System.out.println(m.get());
}
}
測(cè)試時(shí)需要指定啟動(dòng)內(nèi)存大?。?/p>
-Xmx25m
結(jié)果:
[B@6f75e721
[B@6f75e721
null
三、弱引用
弱引用也是用來(lái)描述那些非必須對(duì)象,但是它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生為止。當(dāng)垃圾收集器開(kāi)始工作,無(wú)論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。在JDK 1.2版之后提供了WeakReference類來(lái)實(shí)現(xiàn)弱引用。
應(yīng)用:ThreadLocal;WeakHashMap。
import java.lang.ref.WeakReference;
/**
* @description: 弱引用
*
* 弱引用也是用來(lái)描述那些非必須對(duì)象,但是它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只
* 能生存到下一次垃圾收集發(fā)生為止。當(dāng)垃圾收集器開(kāi)始工作,無(wú)論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只
* 被弱引用關(guān)聯(lián)的對(duì)象。在JDK 1.2版之后提供了WeakReference類來(lái)實(shí)現(xiàn)弱引用。
*
* 應(yīng)用:ThreadLocal
* @author:weirx
* @date:2021/5/19 16:54
* @version:3.0
*/
public class WeakReferenceTest {
public static void main(String[] args) throws InterruptedException {
WeakReference<byte[]> w = new WeakReference<>(new byte[1024 * 1024 * 10]);
System.out.println(w.get());
System.gc();
Thread.sleep(1000);
//只經(jīng)歷一次gc就被回收了
System.out.println(w.get());
}
}
結(jié)果:
[B@6f75e721
null
四、虛引用
虛引用也稱為“幽靈引用”或者“幻影引用”,它是最弱的一種引用關(guān)系。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)取得一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的只是為了能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。在JDK 1.2版之后提供了PhantomReference類來(lái)實(shí)現(xiàn)虛引用。
應(yīng)用:在jvm中,用來(lái)管理直接內(nèi)存(例如NIO中ByteBuffer申請(qǐng)直接內(nèi)存allocateDirect)的回收.會(huì)將虛引用的回收時(shí)間添加到一個(gè)隊(duì)列中。通過(guò)檢測(cè)虛引用可以做一些善后操作。
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 虛引用
* 虛引用也稱為“幽靈引用”或者“幻影引用”,它是最弱的一種引用關(guān)系。一個(gè)對(duì)象是否有虛引用的
* 存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)取得一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛
* 引用關(guān)聯(lián)的唯一目的只是為了能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。在JDK 1.2版之后提供
* 了PhantomReference類來(lái)實(shí)現(xiàn)虛引用
*
* 應(yīng)用:在jvm中,用來(lái)管理直接內(nèi)存(例如NIO中ByteBuffer申請(qǐng)直接內(nèi)存allocateDirect)的回收.會(huì)將虛引用的回收時(shí)間添加到一個(gè)隊(duì)列中。
* @author:weirx
* @date:2021/5/19 17:09
* @version:3.0
*/
public class PhantomReferenceTest {
static class M {
int a = 0;
}
static ReferenceQueue referenceQueue = new ReferenceQueue();
public static void main(String[] args) {
PhantomReference phantomReference = new PhantomReference(new M(), referenceQueue);
//通過(guò)get頁(yè)不能獲取到
System.out.println(phantomReference.get());
List list = new ArrayList();
//模擬線程,不斷增加堆空間占用
new Thread(() -> {
while (true) {
list.add(new byte[1024 * 1024]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(phantomReference.get());
}
}).start();
//模擬垃圾回收線程,可用于做善后處理,比如nio的直接內(nèi)存
new Thread(() -> {
while (true) {
//當(dāng)虛引用對(duì)象被回收時(shí),會(huì)在隊(duì)列里面增加一個(gè)信息,當(dāng)我們獲取到信息就可以對(duì)這個(gè)引用做善后處理
Reference poll = referenceQueue.poll();
if (poll != null) {
System.out.println("虛引用對(duì)象被jvm回收了," + poll);
}
}
}).start();
}
}
結(jié)果:
null
null
null
null
null
null
null
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
at com.cloud.bssp.reference.PhantomReferenceTest.lambda$main$0(PhantomReferenceTest.java:44)
at com.cloud.bssp.reference.PhantomReferenceTest$$Lambda$1/874088044.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
虛引用對(duì)象被jvm回收了,java.lang.ref.PhantomReference@7090cd23