虛擬機如何發起內存回收?— JVM系列(八)

一、OopMap—記錄引用位置

在可達性算法中,可作爲GC Roots的節點需要在全局性的引用(如常量或類靜態屬性)與執行上下文(如棧幀中的本地變量表)中,如果逐個檢查會消耗很多時間。

當系統執行GC,停頓下來時,並不需要一個不漏的檢查完所有執行上下文和全局的引用位置,虛擬機應當有辦法直接得知哪些地方存放着引用。

在HotSpot的實現中,是使用一組稱爲OopMap的數據結構來達到這個目的的。

在類加載完成的時候,HotSpot就把對象內什麼偏移量上是什麼類型的數據計算出來,在JIT編譯過程中,也會在特定的位置記錄下來棧和寄存器中哪些位置是引用。

二、安全點—GC回收的位置

在OopMap的協助下,HotSpot可以快速且準確的完成GC Roots枚舉,但是如果爲每一條指令都生成對應的OopMap,那將會需要大量的額外空間。

只是在特定的位置記錄了這些信息,這些位置稱爲安全點,也就是程序執行時並非在所有地方都能停頓下來開始GC,只有在到達安全點時才能暫停。

安全點的選擇基本上是以程序是否具有讓程序長時間執行的特徵爲準進行選定的。長時間執行的最明顯特徵就是指令序列複用,例如方法調用、循環跳轉、異常跳轉等,所以具有這些功能的指令纔會產生Safepoint。

那麼如何在GC發生時讓所有線程都跑到最近的安全點上再停頓下來呢:

  • 搶先式中斷:讓所有線程全部中斷,如果發現有線程中斷的地方不在安全點上,就恢復線程,讓它跑到安全點上,這種方式一般不會被使用。
  • 主動式中斷:當GC需要中斷線程的時候,僅僅簡單的設置了一個標誌,各個線程主動去輪詢這個標誌,發現中斷標誌爲真時就自己中斷掛起。

三、安全區域—安全點的擴充

使用Safepoint機制保證了程序執行時,在不太長的時間內就會遇到可進入GC的Safepoint。

但是當程序不執行的時候呢,線程無法響應JVM的中斷請求,走到安全的地方去中斷掛起,JVM也顯然不太可能一直等待,這時候,就需要安全區域Safe Region來解決。

安全區域是指在一段代碼片段之中,引用關係不會發生變化,在這個區域中的任意地方開始GC都是安全的。

我們可以把Safe Region看作是被擴展了的SafePoint。

當線程執行到Safe Region中的代碼時,首先標識自己已經進入了Safe Region,那樣,當在這段時間裏JVM將要發起GC時,就可以正常進行了。

在線程要離開安全區域的時候,他要檢查系統是否已經完成了根節點枚舉,如果完成了,線程就繼續執行,否則必須等到收到可以安全離開安全區域的信號爲止。

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