JVM內(nèi)存管理—內(nèi)存回收—枚舉與一致性

在可達性分析之前面臨的問題

可達性分析的時間敏感性,主要體現(xiàn)在搜索根節(jié)點,以及引用一致性

  1. 搜索根節(jié)點:可作為GC Roots的節(jié)點主要在全局性的引用上常量與靜態(tài)屬性)與執(zhí)行上下文棧中的本地變量表)中,但是對于大型應(yīng)用,在方法區(qū)的空間大小就有幾百兆,每次搜索所有 GC Roots 時都將耗費大量的時間
  2. GC停頓:每次進行可達性分析時都需要保證在分析過程中引用關(guān)系的保持不變(引用一致性),這就導(dǎo)致進行GC時必須暫停所有java執(zhí)行線程,即使在號稱不會發(fā)生GC停頓的CMS收集器中,枚舉根節(jié)點時用戶線程也是必須要停頓的。

為了改善上述的性能問題

OopMap(Ordinary object Pointer Map 普通對象指針 Map數(shù)據(jù)結(jié)構(gòu))

HotSpot JVM 在特定的位置存儲棧和寄存器中哪些位置是引用,這樣就不用每次GC時都去遍歷這些區(qū)域,節(jié)省了大量時間。

Safepoint(安全點)
  • 當需要GC時,程序執(zhí)行時并非在所有地方都能停頓下來進行GC,只有到達安全點時才能暫停。
  • 理論上OopMap為了能在任意位置進行暫停GC,必須為每條命令生成對應(yīng)的OopMap對象,這將需要大量的空間,GC空間成本將會增加,實際上HotSpot只會在安全點生成對應(yīng)的OopMap來記錄這些引用。

GC發(fā)生時,應(yīng)用程序如何暫停?

  • 搶先式暫停:不需要線程的執(zhí)行代碼進行配合,而是在GC時直接中斷暫停,然后判斷哪個線程沒有落在安全點上,如果沒有落在安全點則恢復(fù)線程使其運行到最近的安全點上。
  • 主動式暫停:設(shè)置一個標志,每個線程執(zhí)行到安全點或者創(chuàng)建對象需要分配內(nèi)存空間的時候主動輪詢這個標志,發(fā)現(xiàn)為中斷標志時使自己中斷掛起。這是所有JVM的主要實現(xiàn)方式。
Safe Region(安全區(qū)域)
  • 為了解決處于sleep和blocked狀態(tài)的線程沒有辦法響應(yīng)JVM的中斷請求(或者主動輪詢中斷標志),始終沒有辦法走到安全點
  • 安全區(qū)指的是一段代碼之中,引用關(guān)系不會發(fā)生變化,在這個區(qū)域中的任意地方開始對這個線程 GC 都是安全的。

過程

  • 在線程執(zhí)行到Safe Region的代碼時,首先標識自己已經(jīng)進入了Safe Region,然后線程可以繼續(xù)運行,在這期間可以sleep或者blocked,但是離開安全區(qū)域必須檢查系統(tǒng)是否已經(jīng)完成了根節(jié)點的枚舉或者是整個GC過程,如果為是,則離開,否則等待直到為是。
  • 由于線程sleep或blocked時引用關(guān)系不再變化,而引用關(guān)系不再的變化的代碼位于安全區(qū)域,換句話說sleep或blocked總是在安全區(qū)域內(nèi),所以GC時不用使sleep或blocked的線程跑到安全點上,因為位于安全區(qū)域的線程不管狀態(tài)如何,都能保證在這段時間內(nèi)引用是不在變化的。

總結(jié)

  • 每個安全點、安全區(qū)域指的是某一個線程執(zhí)行的位置和區(qū)間,當發(fā)生GC時,每個線程都到達各自對應(yīng)的最近的安全點或安全區(qū)域,就可以保證引用一致性了。
  • JVM負責設(shè)置中斷和恢復(fù)安全點的所有線程,GC 面向的是所有線程。
  • 可達性分析后進行回收時線程是繼續(xù)執(zhí)行還是暫停取決于垃圾收集器的執(zhí)行方式(并行還是串行的)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容