無論是通過引用計數(shù)算法判斷對象的引用數(shù)量,還是通過可達性分析算法判斷對象是否引用鏈可達霹陡,判定對象是否存活都和“引用”離不開關系惠勒。
在JDK 1.2版之后迁央,Java對引用的概念進行了擴充,將引用分為強引用(Strongly Re-ference)僵刮、軟引用(Soft Reference)据忘、弱引用(Weak Reference)和虛引用(Phantom Reference)4種,這4種引用強度依次逐漸減弱搞糕。
一勇吊、強引用
強引用是最傳統(tǒng)的“引用”的定義,是指在程序代碼之中普遍存在的引用賦值窍仰,即類似“Object obj=new Object()”這種引用關系汉规。無論任何情況下,只要強引用關系還存在驹吮,垃圾收集器就永遠不會回收掉被引用的對象针史。
二、軟引用
軟引用是用來描述一些還有用碟狞,但非必須的對象啄枕。只被軟引用關聯(lián)著的對象,在系統(tǒng)將要發(fā)生內存溢出異常前族沃,會把這些對象列進回收范圍之中進行第二次回收频祝,如果這次回收還沒有足夠的內存,才會拋出內存溢出異常竭业。在JDK 1.2版之后提供了SoftReference類來實現(xiàn)軟引用智润。
應用場景:緩存。
import java.lang.ref.SoftReference;
/**
* @description: 軟引用
* ·軟引用是用來描述一些還有用未辆,但非必須的對象窟绷。只被軟引用關聯(lián)著的對象,在系統(tǒng)將要發(fā)生內
* 存溢出異常前咐柜,會把這些對象列進回收范圍之中進行第二次回收兼蜈,如果這次回收還沒有足夠的內存,
* 才會拋出內存溢出異常拙友。在JDK 1.2版之后提供了SoftReference類來實現(xiàn)軟引用为狸。
*
* 應用場景:緩存
*
* @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());
//分配一個強引用的byte,看看當堆空間不足時遗契,是否會將軟引用回收辐棒。
// 需要啟動時將最大堆內存設置為25M,當內存不足后發(fā)生第二次垃圾回收之后在獲取軟引用就是null。
byte[] bytes = new byte[1024 * 1024 * 12];
System.out.println(m.get());
}
}
測試時需要指定啟動內存大醒:
-Xmx25m
結果:
[B@6f75e721
[B@6f75e721
null
三泰涂、弱引用
弱引用也是用來描述那些非必須對象,但是它的強度比軟引用更弱一些辐怕,被弱引用關聯(lián)的對象只能生存到下一次垃圾收集發(fā)生為止逼蒙。當垃圾收集器開始工作,無論當前內存是否足夠寄疏,都會回收掉只被弱引用關聯(lián)的對象是牢。在JDK 1.2版之后提供了WeakReference類來實現(xiàn)弱引用。
應用:ThreadLocal陕截;WeakHashMap驳棱。
import java.lang.ref.WeakReference;
/**
* @description: 弱引用
*
* 弱引用也是用來描述那些非必須對象,但是它的強度比軟引用更弱一些艘策,被弱引用關聯(lián)的對象只
* 能生存到下一次垃圾收集發(fā)生為止蹈胡。當垃圾收集器開始工作,無論當前內存是否足夠朋蔫,都會回收掉只
* 被弱引用關聯(lián)的對象罚渐。在JDK 1.2版之后提供了WeakReference類來實現(xiàn)弱引用。
*
* 應用: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());
}
}
結果:
[B@6f75e721
null
四驯妄、虛引用
虛引用也稱為“幽靈引用”或者“幻影引用”荷并,它是最弱的一種引用關系。一個對象是否有虛引用的存在青扔,完全不會對其生存時間構成影響源织,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯(lián)的唯一目的只是為了能在這個對象被收集器回收時收到一個系統(tǒng)通知微猖。在JDK 1.2版之后提供了PhantomReference類來實現(xiàn)虛引用诈胜。
應用:在jvm中凳厢,用來管理直接內存(例如NIO中ByteBuffer申請直接內存allocateDirect)的回收.會將虛引用的回收時間添加到一個隊列中。通過檢測虛引用可以做一些善后操作。
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.List;
/**
* @description: 虛引用
* 虛引用也稱為“幽靈引用”或者“幻影引用”垦写,它是最弱的一種引用關系诚撵。一個對象是否有虛引用的
* 存在捧韵,完全不會對其生存時間構成影響丝蹭,也無法通過虛引用來取得一個對象實例。為一個對象設置虛
* 引用關聯(lián)的唯一目的只是為了能在這個對象被收集器回收時收到一個系統(tǒng)通知犁享。在JDK 1.2版之后提供
* 了PhantomReference類來實現(xiàn)虛引用
*
* 應用:在jvm中余素,用來管理直接內存(例如NIO中ByteBuffer申請直接內存allocateDirect)的回收.會將虛引用的回收時間添加到一個隊列中。
* @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);
//通過get頁不能獲取到
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的直接內存
new Thread(() -> {
while (true) {
//當虛引用對象被回收時,會在隊列里面增加一個信息视乐,當我們獲取到信息就可以對這個引用做善后處理
Reference poll = referenceQueue.poll();
if (poll != null) {
System.out.println("虛引用對象被jvm回收了," + poll);
}
}
}).start();
}
}
結果:
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)
虛引用對象被jvm回收了,java.lang.ref.PhantomReference@7090cd23