六:HotSpot對象存活判定和垃圾回收算法的實現(是如何發起內存回收的)

首先需要明確

如果逐個檢查可以作爲GC Roots節點的引用的話,是非常耗時的(很多應用一個方法區就幾百兆)

需要保證在分析的過程中對象的引用關係不能發生改變,否則就不能夠保證結果的正確性。因此在GC過程中,必須要停頓(枚舉根節點是必須要停頓的)

 

枚舉根節點

因此HotSpot中通過使用一組OopMap的數據結構來得知哪些地方存放有對象的引用,在OopMap的協助下,HotSpot能夠快速且準確地完成GCRoots的枚舉。

 

安全點

什麼是安全點?

通過上面的那種方法,雖然可以減少枚舉時間,但是由於可能導致引用關係變化,或者說可能導致OopMap內容變化的指令非常多,如果爲每一條指令都生成對應的OopMap,那將會需要大量的額外空間,這樣GC的空間成本將會變得很高。爲了避免這種情況的發生,HotSpot只在特定的位置記錄這些信息,這些位置就被稱爲安全點(safe-point),即程序執行時並非在所有地方都能停頓下來開始GC,只有在到達安全點時才能暫停(因爲這個時候對象的引用關係不會發生變化)

如何選擇安全點?

既不能太少以致於讓GC等待時間太長,也不能過於頻繁以致於過分增大運行時的負荷。所以,安全點的選定基本上是以程序“是否具有讓程序長時間執行的特徵”爲標準進行選定的——因爲每條指令執行的時間都非常短暫,程序不太可能因爲指令流長度太長這個原因而過長時間運行,“長時間執行”的最明顯特徵就是指令序列複用,例如方法調用、循環跳轉、異常跳轉等,所以具有這些功能的指令纔會產生Safepoint。

如何在GC時讓所有線程能夠到達安全點?

通過主動式中斷:當GC需要中斷線程的時候,不直接對線程操作,僅僅簡單地設置一個標誌,各個線程執行時主動去輪詢這個標誌,發現中斷標誌爲真時就自己中斷掛起。輪詢標誌的地方和安全點是重合的,另外再加上創建對象需要分配內存的地方。

HotSpot中,可以讓虛擬機在需要暫停線程時,把某條指令需要用到的內存頁設置爲不可讀,線程執行到這條指令時就會產生一個自陷異常信號,在預先註冊的異常處理器中暫停線程實現等待,這樣一條彙編指令便完成安全點輪詢和觸發線程中斷。

 

安全區域

導入:

線程處於Sleep狀態或者Blocked狀態,這時候線程無法響應JVM的中斷請求,不能夠到達安全的地方去中斷掛起,JVM也顯然不太可能等待線程重新被分配CPU時間。對於這種情況,就需要安全區域(Safe Region)來解決。

原理:

安全區域是指在一段代碼片段之中,引用關係不會發生變化。在這個區域中的任意地方開始GC都是安全的。我們也可以把Safe Region看做是被擴展了的Safepoint。

在線程執行到Safe Region中的代碼時,首先標識自己已經進入了Safe Region,那樣,當在這段時間裏JVM要發起GC時,就不用管標識自己爲Safe Region狀態的線程了。在線程要離開Safe Region時,它要檢查系統是否已經完成了根節點枚舉(或者是整個GC過程),如果完成了,那線程就繼續執行,否則它就必須等待直到收到可以安全離開Safe-Region的信號爲止。

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