-XX:MaxTenuringThreshold 默認 15,但對象並非必須經歷 15 次 Minor GC 才晉升老年代。HotSpot 在每次 Minor GC 後動態計算新的存活年齡閾值,取 age 與 MaxTenuringThreshold 的較小值。
size_t desired_survivor_size = survivor_capacity * TargetSurvivorRatio / 100; // 目標Survivor佔用量(默認50%)
size_t total = 0;
int age = 1;
while (age < table_size) {
total += sizes[age]; // 累加各年齡對象大小
if (total > desired_survivor_size) break; // 超過目標則停止
age++;
}
int result = Math.min(age, MaxTenuringThreshold);
public class GCTenuringThreshold {
public static void main(String[] args) throws Exception {
GCMemoryObject o1 = new GCMemoryObject(2); // 512KB
GCMemoryObject o2 = new GCMemoryObject(8); // 2MB
GCMemoryObject o3 = new GCMemoryObject(8);
GCMemoryObject o4 = new GCMemoryObject(8);
o2 = null; o3 = null;
GCMemoryObject o5 = new GCMemoryObject(8);
Thread.sleep(4000);
o2 = new GCMemoryObject(8); o3 = new GCMemoryObject(8);
o2 = null; o3 = null; o5 = null;
GCMemoryObject o6 = new GCMemoryObject(8);
Thread.sleep(5000);
}
}
class GCMemoryObject { byte[] bytes; GCMemoryObject(int m) { bytes = new byte[1024*256*m]; } }
參數 -Xms20M -Xmx20M -Xmn10M -XX:+UseSerialGC,jstat -gcutil pid 1000 10 觀察:o1 在第 2 次 Minor GC 即晉升老年代(年齡 1),因首次 GC 後動態閾值計算為 1。
InitialTenuringThreshold=7,之後動態計算(規則更複雜);-XX:-UseAdaptiveSizePolicy 固定為 MaxTenuringThreshold啟動參數添加 -XX:+PrintTenuringDistribution,日誌輸出:
Desired survivor size 1048576 bytes, new threshold 7 (max 15)
new threshold 即當前動態年齡閾值。