最近面試了一個連引用都不懂的Java程序員

最近就說到了一個面試題

談談對Java中幾種引用的理解。

因此打算以該面試題爲例子,寫篇文章說說在Java中引用是什麼以及怎麼用。 【劃重點:給你三秒鐘時間思考,如果是你,該如何回答面試官的這個問題呢】

引用是什麼

【劃重點】在Java中引用包括:

  • FinalReference 強引用
  • SoftReference 軟引用
  • WeakReference 弱引用
  • PhantomReference 虛引用

那麼爲什麼會提供這四種引用呢,主要原因有:

  • 方便Jvm進行垃圾回收
  • 方便開發人員使用,開發人員可以靈活的決定某些對象的生命週期

日常開發如何使用

學以致用,那麼這幾個引用在日常中我們如何進行使用呢? 接下來我會給出相關demo!!!

FinalReference 強引用

類似於 Object o = new Object() 這類的引用,創建一個對象後,該引用會被保存在JVM棧中,而且只要強引用存在,垃圾回收器就不會回收掉被引用的對象。

日常使用

強引用的例子比比皆是,因爲在日常開發中我們是會經常去new一個對象的,而該new出來的對象便是強引用的,也就是說只要該引用存在,垃圾回收器就不會回收掉。 【劃重點:JVM怎麼知道引用在不在?】

SoftReference 軟引用

軟引用關聯的對象,在內存不夠的情況下,會把這些軟引用關聯的對象列入垃圾回收範圍中,然後進行回收,也就是說軟引用並非是完全安全的,在內存不夠的情況下是會被垃圾回收器回收掉的。

給出demo

 

2.png

 

 

通過註釋便可以知道,我這裏實例化了多個大對象,然後放入softReferences數組中,之後便遍歷打印出其中的對象的命名,打印結果如下

 

3.png

 

 

可以通過結果看出,前面四個對象因爲內存不夠而被垃圾回收器回收了。

日常使用

在我司的項目中,部分是使用軟引用來保存從數據庫中取出的數據,具體是做了一箇中間層的封裝,該中間層的作用就是在get出數據的時候會去判斷數據是否爲null,如果是爲null再次從數據庫讀取,讀取後再放入軟引用的集合中,這樣的做法是可以避免內存溢出。

WeakReference 弱引用

弱引用比軟引用更弱,被弱引用關聯的對象只能存活到發生下一次垃圾回收之前,也就是說當發生GC時,無論當前內存是否足夠,都會被回收掉。

給出demo

 

4.png

 

 

代碼很簡短,就是先構建一個弱引用對象,然後在gc前先打印出來證明它存在過,之後手動調用gc,再次打印,可以看出已經沒了。運行結果如下

 

5.png

 

 

PhantomReference 虛引用

虛引用和上面不同的地方在於,一個對象是否有虛引用的存在,完全不會對其生存時間構成如何影響,並且也無法通過虛引用來獲取一個對象的實例,也就是說跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收。

那麼這樣就很容易產生疑問了,虛引用的作用又是什麼呢?

作用就是能在這個對象被收集器回收時收到一個系統通知,實現追蹤垃圾收集器的回收動作,比如在對象被回收的時候,會調用該對象的finalize方法。

在給出相關demo前,要先介紹一個

ReferenceQueue 引用隊列

ReferenceQueue 引用其實也可以歸納爲引用中的一員,可以和上述三種引用類型組合使用【軟引用、弱引用、虛引用】。

那麼它有何作呢?

在創建Reference時,手動將Queue註冊到Reference中,而當該Reference所引用的對象被垃圾收集器回收時,JVM會將該Reference放到該隊列中,而我們便可以對該隊列做些其他業務,相當於一種通知機制。

給出demo

 

6.png

 

 

可以從demo中看出隊列的用法,運行打印結果如下

 

7.png

 

 

我們可以從結果中看到先是從引用中get出來的對象爲null,證明上面說的無法通過虛引用來獲取一個對象的實例,並且在回收後會被放入隊列中。

和Reference相關的概念

首先爲了方便JVM進行管理,Reference是有狀態的,可以分爲以下四種狀態

  • active 一般來說內存一開始被分配的狀態,而當被引用的對象的可達性發生變化後gc就會將引用放入pending隊列並將其狀態改爲pending狀態。
  • pending 指的是準備要被放進pending隊列的對象。
  • enqueue 指的是對象的內存已經被回收了。
  • inactive 這是最終的狀態,不能再變爲其它狀態。

JVM怎麼知道引用在不在

關於JVM怎麼知道引用在不在,這就涉及到了JVM的可達性分析算法了 JVM的可達性分析算法的簡單思路就是通過一系列GC Roots作爲出發點,向下搜索,搜索所走過的路徑稱爲引用鏈,當一個對象到GC Roots沒有任何引用鏈,即表明從GC Roots到這個對象不可達時,證明此對象不可用,可被回收。如下圖所示

 

6.png

 

 

對象4、5、6都是可被回收的。 那麼問題來了,哪些對象可以作爲GC Roots呢? 這裏給出幾個,如下

  • 虛擬機棧中引用的對象

  • 方法區中類靜態屬性引用的對象

  • 方法區中常量引用的對象

  • 本地方法棧JNI引用的對象

具體的想要深入研究的可以自行百度&谷歌,或者等我後面深入分析。

最後的最後

該篇文章基本解答了【談談對Java中幾種引用的理解】,如果想要更深入的研究,就要從源碼入手瞭解了。 下次遇見這種面試題,基本上就不慌了,因爲實際上只要認真看完該篇文章並且記住幾個關鍵的地方,基本上就不會被面試官問倒了,並且該篇文章後面也解答了【JVM怎麼知道引用在不在】和【哪些對象可以作爲GC Roots】的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章