Java面試題沖刺第二十九天–JVM3

面試題1:如何判斷對象是否存活

對於判斷對象是否存活,主要是兩種基本算法,引用計數和可達性分析,目前java主要采用的是可達性分析算法

1.引用計數算法

判斷對象是否存活的方式如:在對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加一;當引用失效時,計數器值就減一;任何時刻計數器為零的對象就是不可能再被使用的。

其優點是實現簡單,判定效率高;缺點是該算法有很多例外情況要考慮,必須要配合大量額外處理才能保證正確地工作,且存在一個基本的難題,也就是很難處理循環引用關系。

2.可達性分析算法

其原理簡單來說,就是將對象及其引用關系看作一個圖,通過一系列稱為GC Roots的根對象作為起始節點集,從這些節點開始,通過引用關系向下搜索,搜索過程所走過的路徑稱為引用鏈(Reference Chain),如果一個對象和 GC Roots 之間不可達,也就是不存在引用鏈條,那麼即認為是可回收對象。JVM會把虛擬機棧和本地方法棧中正在引用的對象、靜態屬性引用的對象和常量,作為 GC Roots。

在這裡插入圖片描述

如圖所示,對象object 5、object 6、object 7雖然互有關聯,但是它們到GC Roots是不可達的, 因此它們將會被判定為可回收的對象。

面試題2:哪些對象可以作為GC Roots?

在Java技術體系裡面,固定可作為GC(Garbage Collector) Roots的對象包括以下幾種:

在這裡插入圖片描述

常說的GC(Garbage Collector) roots,特指的是垃圾收集器的根對象(GC Root Object),也叫作稱為GC垃圾回收根(GC Root),GC會收集那些不是GC roots且沒有被GC roots引用的對象清理掉。

一個對象可以屬於多個root,GC root存在幾下種:

  • 虛擬機棧中引用 的對象
    • 如各個線程被調用的方法堆棧中使用到的 參數、局部變量、臨時變量等。
  • 方法區中類靜態屬性引用的對象
    • 如Java 類的引用類型靜態變量
  • 方法區中常量引用的對象
    • 如字符串常量池(String Table) 裡的引用
  • 本地方法棧內 JNI(通常說的本地方法)引用的對象
  • 所有被同步鎖 (synchronized關鍵字) 持有的對象
  • Java 虛擬機內部的引用
    • 如基本數據類型對應的Class對象,一些常駐的異常對象(比如 NullPointExcepiton、OutOfMemoryError)、系統類加載器等。
  • 反映 Java 虛擬機內部情況的 JMXBean、JVMTI 中註冊的回調、本地代碼緩存等。
  • 除瞭固定的 GC Roots 集合以外,根據用戶所選用的垃圾收集器以及當前回收的內存區域不同,還可以有其他對象 臨時性 地加入,共同構成完整 GC Roots 集合。

面試題3:你瞭解的對象引用方式都有哪些?

該回答來自極客時間《Java核心技術面試精講第四講》的評論部分。

在Java語言中,除瞭基本數據類型外,其他的都是指向各類對象的對象引用;Java中根據其生命周期的長短,將引用分為強引用、弱引用、軟引用、虛引用4類。

1 強引用

我們平常典型編碼Object obj = new Object()中的obj就是強引用。通過關鍵字new創建的對象所關聯的引用就是強引用。 當JVM內存空間不足,JVM寧願拋出OutOfMemoryError運行時錯誤(OOM),使程序異常終止,也不會靠隨意回收具有強引用的存活對象來解決內存不足的問題。對於一個普通的對象,如果沒有其他的引用關系,隻要超過瞭引用的作用域或者顯式地將相應(強)引用賦值為null,就是可以被垃圾收集的瞭,具體回收時機還是要看垃圾收集策略。

2 軟引用

軟引用通過SoftReference類實現。

軟引用的生命周期比強引用短一些。隻有當 JVM 認為內存不足時,才會去試圖回收軟引用指向的對象:即JVM 會確保在拋出OutOfMemoryError之前,清理軟引用指向的對象。軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。後續,我們可以調用ReferenceQueue.poll()方法來檢查是否有它所關心的對象被回收。如果隊列為空,將返回一個null,否則該方法返回隊列中前面的一個Reference對象。

應用場景:軟引用通常用來實現內存敏感的緩存。如果還有空閑內存,就可以暫時保留緩存,當內存不足時清理掉,這樣就保證瞭使用緩存的同時,不會耗盡內存。

3 弱引用

弱引用通過WeakReference類實現。

弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現瞭具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。由於垃圾回收器是一個優先級很低的線程,因此不一定會很快回收弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。

應用場景:弱引用同樣可用於內存敏感的緩存。

4 虛引用

虛引用也叫幻象引用,通過PhantomReference類來實現。

無法通過虛引用訪問對象的任何屬性或函數。幻象引用僅僅是提供瞭一種確保對象被 finalize 以後,做某些事情的機制。如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。

ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);

程序可以通過判斷引用隊列中是否已經加入瞭虛引用,來瞭解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前采取一些程序行動。

應用場景:可用來跟蹤對象被垃圾回收器回收的活動,當一個虛引用關聯的對象被垃圾收集器回收之前會收到一條系統通知。

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: