JVM垃圾收集器(2)

此文已由做者趙計剛薪受權網易雲社區發佈。html

歡迎訪問網易雲社區,瞭解更多網易技術產品運營經驗。算法


一、G1安全



說明:服務器

  • 從上圖來看,G1與CMS相比,僅在最後的"篩選回收"部分不一樣(CMS是併發清除),實際上G1回收器的整個堆內存的劃分都與其餘收集器不一樣。併發

  • CMS須要配合ParNew,G1可單獨回收整個空間spa

原理:.net

  • G1收集器將整個堆劃分爲多個大小相等的Region線程

  • G1跟蹤各個region裏面的垃圾堆積的價值(回收後所得到的空間大小以及回收所需時間長短的經驗值),在後臺維護一張優先列表,每次根據容許的收集時間,優先回收價值最大的region,這種思路:在指定的時間內,掃描部分最有價值的region(而不是掃描整個堆內存),並回收,作到儘量的在有限的時間內獲取儘量高的收集效率。設計

運做流程:orm

  • 初始標記:標記出全部與根節點直接關聯引用對象。須要STW

  • 併發標記:遍歷以前標記到的關聯節點,繼續向下標記全部存活節點。

    • 在此期間全部變化引用關係的對象,都會被記錄在Remember Set Logs中

  • 最終標記:標記在併發標記期間,新產生的垃圾。須要STW

  • 篩選回收:根據用戶指定的指望回收時間回收價值較大的對象(看"原理"第二條)。須要STW

優勢:

  • 停頓時間能夠預測:咱們指定時間,在指定時間內只回收部分價值最大的空間,而CMS須要掃描整個年老代,沒法預測停頓時間

  • 無內存碎片:垃圾回收後會整合空間,CMS採用"標記-清理"算法,存在內存碎片

  • 篩選回收階段:

    • 因爲只回收部分region,因此STW時間咱們可控,因此不須要與用戶線程併發爭搶CPU資源,而CMS併發清理須要佔據一部分的CPU,會下降吞吐量。

    • 因爲STW,因此不會產生"浮動垃圾"(即CMS在併發清理階段產生的沒法回收的垃圾)

適用範圍:

  • 追求STW短:若ParNew/CMS用的挺好,就用這個;若不符合,用G1

  • 追求吞吐量:用Parallel Scavenge/Parallel Old,而G1在吞吐量方面沒有優點

 

二、幾點注意

問題1、G1之外的其餘收集器在回收垃圾的時候:要不僅是掃描年輕代,要不僅是掃描年老代。在年輕代的回收過程當中,若是舊生代中的對象引用了年輕代的對象,那麼咱們只掃描年輕代就不行了,可是因爲年老代通常而言是年輕代的3倍大小,若是年輕代、年老代一塊兒去掃描的話,效率會急劇降低,這個問題怎麼處理?

:JVM採用remember set來作的這個事兒,當發現一個引用對象被賦值時,JVM發出一個write barrier指令來暫時中斷寫操做,檢查被賦值的引用對象是否是處於年老代,且其引用的對象是否是處於新生代(便是不是年老代對象引用了年輕代對象),若是是,將相關引用信息記錄到remember set。以後的掃描,咱們會從根集合+remember set向下進行掃描。(也就是說真正的根集合,是JVM定義的根集合+remember set)

 

問題2、G1收集器爲了作到GC時間可預測,採用掃描部分價值最大的region來實現,那麼若是這部分region中的對象被其餘region中的對象所引用,那麼僅掃描前者可能就不行了,可是若是掃描所有region的話,又沒法作到GC時間可預測,效率會大大降低,怎麼辦?

:G1同理,爲每個region分配一個remember set,當發現一個引用對象被賦值時,JVM發出一個write barrier指令來暫時中斷寫操做,檢查被賦值的引用對象與其引用的對象是否是處於不一樣的region(eg.a=b;檢查a與b是否是在不一樣的region),若是是,將相關引用信息記錄到當前region的remember set。以後的掃描,咱們會從根集合+remember set向下進行掃描。

 

問題3、CMS與G1在併發標記的時候若發部分引用對象的引用關係發生了變化,怎麼處理才能讓從新標記的時候僅僅掃描出這些變化?

:在併發標記期間,對象的引用關係若發生了變化,這些相關的記錄就會記錄到remember set logs;在從新標記階段,將該logs的信息加入到remember set中去,而後再從remember set去向下trace節點。


免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐

更多網易技術、產品、運營經驗分享請點擊


相關文章:
【推薦】 移動端推廣APP防做弊機制之依我見
【推薦】 淺談代碼結構的設計

相關文章
相關標籤/搜索