作者:CodeBear的園子
來源:www.cnblogs.com/CodeBear/p/12447554.html
Java中的四種參考
Java中有四種參考型別:強參考、軟參考、弱參考、虛參考,
Java為什么要設計這四種參考
Java的記憶體分配和記憶體回收,都不需要程式員負責,都是由偉大的JVM去負責,一個物件是否可以被回收,主要看是否有參考指向此物件,說的專業點,叫可達性分析,
Java設計這四種參考的主要目的有兩個:
-
可以讓程式員通過代碼的方式來決定某個物件的生命周期;
-
有利用垃圾回收,
強參考
強參考是最普遍的一種參考,我們寫的代碼,99.9999%都是強參考:
Object o = new Object();
這種就是強參考了,是不是在代碼中隨處可見,最親切,
只要某個物件有強參考與之關聯,這個物件永遠不會被回收,即使記憶體不足,JVM寧愿拋出OOM,也不會去回收,
那么什么時候才可以被回收呢?當強參考和物件之間的關聯被中斷了,就可以被回收了,
我們可以手動把關聯給中斷了,方法也特別簡單:
o = null;
我們可以手動呼叫GC,看看如果強參考和物件之間的關聯被中斷了,資源會不會被回收,為了更方便、更清楚的觀察到回收的情況,我們需要新寫一個類,然后重寫finalize方法,下面我們來進行這個實驗:
public class Student { @Override
protected void finalize() throws Throwable {
System.out.println("Student 被回收了");
}
}
public static void main(String[] args) {
Student student = new Student();
student = null;
System.gc();
}
運行結果:
Student 被回收了
可以很清楚的看到資源被回收了,
當然,在實際開發中,千萬不要重寫finalize方法
在實際的開發中,看到有一些物件被手動賦值為NULL,很大可能就是為了“特意提醒”JVM這塊資源可以進行垃圾回收了,點擊這里獲取一份 JVM 實戰教程,
軟參考
下面先來看看如何創建一個軟參考:
SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());
軟參考就是把物件用SoftReference包裹一下,當我們需要從軟參考物件獲得包裹的物件,只要get一下就可以了:
SoftReference<Student>studentSoftReference=new SoftReference<Student>(new Student());
Student student = studentSoftReference.get();
System.out.println(student);
軟參考有什么特點呢:
當記憶體不足,會觸發JVM的GC,如果GC后,記憶體還是不足,就會把軟參考的包裹的物件給干掉,也就是只有在記憶體不足,JVM才會回收該物件,
還是一樣的,必須做實驗,才能加深印象:
SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]);
System.out.println(softReference.get());
System.gc();
System.out.println(softReference.get());
byte[] bytes = new byte[1024 * 1024 * 10];
System.out.println(softReference.get());
我定義了一個軟參考物件,里面包裹了byte[],byte[]占用了10M,然后又創建了10Mbyte[],
運行程式,需要帶上一個引數:
-Xmx20M
代表最大堆記憶體是20M,
運行結果:
[B@11d7fff
[B@11d7fff
null
可以很清楚的看到手動完成GC后,軟參考物件包裹的byte[]還活的好好的,但是當我們創建了一個10M的byte[]后,最大堆記憶體不夠了,所以把軟參考物件包裹的byte[]給干掉了,如果不干掉,就會拋出OOM,
軟參考到底有什么用呢?比較適合用作快取,當記憶體足夠,可以正常的拿到快取,當記憶體不夠,就會先干掉快取,不至于馬上拋出OOM,說到快取,大家可以關注微信公眾號Java技術堆疊獲取更多干貨,
弱參考
弱參考的使用和軟參考類似,只是關鍵字變成了WeakReference:
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1024\*1024\*10]);
System.out.println(weakReference.get());
弱參考的特點是不管記憶體是否足夠,只要發生GC,都會被回收:
WeakReference<byte[]> weakReference = new WeakReference<byte[]>(new byte[1]);
System.out.println(weakReference.get());
System.gc();
System.out.println(weakReference.get());
運行結果:
[B@11d7fffnull
可以很清楚的看到明明記憶體還很充足,但是觸發了GC,資源還是被回收了,
弱參考在很多地方都有用到,比如ThreadLocal、WeakHashMap,
虛參考
虛參考又被稱為幻影參考,我們來看看它的使用:
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
System.out.println(reference.get());
虛參考的使用和上面說的軟參考、弱參考的區別還是挺大的,我們先不管ReferenceQueue 是個什么鬼,直接來運行:
null
竟然列印出了null,我們來看看get方法的原始碼:
public T get() {
return null;
}
這是幾個意思,竟然直接回傳了null,
這就是虛參考特點之一了:無法通過虛參考來獲取對一個物件的真實參考,
那虛參考存在的意義是什么呢?這就要回到我們上面的代碼了,我們把代碼復制下,以免大家再次往上翻:
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<byte[]> reference = new PhantomReference<byte[]>(new byte[1], queue);
System.out.println(reference.get());
創建虛參考物件,我們除了把包裹的物件傳了進去,還傳了一個ReferenceQueue,從名字就可以看出它是一個佇列,
虛參考的特點之二就是 虛參考必須與ReferenceQueue一起使用,當GC準備回收一個物件,如果發現它還有虛參考,就會在回收之前,把這個虛參考加入到與之關聯的ReferenceQueue中,
我們來用代碼實踐下吧:
ReferenceQueue queue = new ReferenceQueue();
List<byte[]> bytes = new ArrayList<>();
PhantomReference<Student> reference = new PhantomReference<Student>(new Student(),queue);
new Thread(() -> {
for (int i = 0; i < 100;i++ ) {
bytes.add(new byte[1024 * 1024]);
}
}).start();
new Thread(() -> {
while (true) {
Reference poll = queue.poll();
if (poll != null) {
System.out.println("虛參考被回收了:" + poll);
}
}
}).start();
Scanner scanner = new Scanner(System.in);
scanner.hasNext();
}
運行結果:
Student 被回收了
虛參考被回收了:java.lang.ref.PhantomReference@1ade6f1
我們簡單的分析下代碼:
第一個執行緒往集合里面塞資料,隨著資料越來越多,肯定會發生GC,
第二個執行緒死回圈,從queue里面拿資料,如果拿出來的資料不是null,就列印出來,
從運行結果可以看到:當發生GC,虛參考就會被回收,并且會把回收的通知放到ReferenceQueue中,
虛參考有什么用呢?在NIO中,就運用了虛參考管理堆外記憶體,
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/49422.html
標籤:Java
