首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Parallel GC 悲觀策略深度解析:為何 Young GC 觸發前會預檢 Old 區空間?

     編輯:Java 相關知識

運行參數 -Xms30m -Xmx30m -Xmn10m -XX:+UseParallelGC 執行特定分配代碼,按常規邏輯應觸發 4 次 Minor GC,實際卻出現 3 次 Minor GC + 2 次 Full GC。根因在於 Parallel Scavenge GC 的「悲觀策略」:在 Young GC 執行前後雙重預檢 Old 區剩餘空間,寧可提前觸發 Full GC 也要避免 Young GC 後大量對象晉升導致 Old 區 OOM。

代碼驗證場景

List caches = new ArrayList<>();
for (int i = 0; i < 7; i++) caches.add(new byte[3*1024*1024]); // 3MB
caches.clear();
for (int i = 0; i < 2; i++) caches.add(new byte[3*1024*1024]);
Thread.sleep(10000);


悲觀策略雙重檢查邏輯(源碼級解析)

檢查 1:Young GC 執行前預檢

boolean should_attempt_scavenge() {
    size_t avg_promoted = padded_average_promoted_in_bytes(); // 歷史平均晉升量
    size_t promotion_estimate = MIN2(avg_promoted, young_gen.used_in_bytes());
    return promotion_estimate < old_gen.free_in_bytes(); // 不夠則放棄 YGC,直接 FGC
}

取「歷史平均晉升量」與「當前新生代已用量」較小值,若大於 Old 區剩餘空間,則跳過 YGC 直接觸發 Full GC。

檢查 2:Young GC 執行後預檢

bool should_full_GC(size_t old_free_in_bytes) {
    return padded_average_promoted_in_bytes() > old_free_in_bytes; // 平均晉升量 > Old剩餘 → 觸發 FGC
}

YGC 完成後,若歷史平均晉升量超過 Old 區剩餘空間,立即觸發 Full GC。

運行過程推演(單位:MB)

循環EdenOldYGCFGC說明
13000
26000
33610首次YGC,3MB晉升
46610
531220
661220
731831YGC後Old剩2MB < 平均晉升6MB → 觸發FGC
861831
93332YGC前預檢:min(6,6)=6MB > Old剩餘 → 跳過YGC直觸發FGC

設計動機與對比

悲觀策略假設程式穩態運行時每次 YGC 晉升量固定,提前檢查避免「YGC 後晉升導致 Old 區 OOM 再 Full GC」的雙重開銷。這也是為何有時 Old 區未滿卻觸發 Full GC 的原因。

思考題:將參數改為 -XX:+UseSerialGC 運行會如何?歡迎實驗驗證。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved