天天看點

《深入了解java虛拟機-JVM進階特性與最佳實踐》讀書筆記 垃圾收集器與記憶體配置設定政策

周志明《深入了解java虛拟機-JVM進階特性與最佳實踐》讀書筆記 p69-100 垃圾收集器與記憶體配置設定政策

1.垃圾收集算法:

1.1 标記-清除算法 Mark-Sweep

首先标記需要清除需要回收的對象,在标記完成後統一回收所有被标記的對象。

兩個過程效率都不高。标記清除之後會産生大量不連續額記憶體碎片。

1.2 複制算法

将可用記憶體按容量劃分為大小相等的兩塊,每次隻使用其中的一塊。每次是對整個半區進行記憶體回收。記憶體配置設定時也不用考慮記憶體碎片等複雜情況。隻要移動堆頂指針,按順序配置設定即可,實作簡單,運作高效。

隻是這種算法的代價是将記憶體縮小為原來的一半。

新生代對象95%是朝生夕死Hotspot虛拟機預設Eden和Survivor的大小比例是8:1.

當Survivor空間不夠用時,需要依賴其他記憶體(這裡指老年代)進行配置設定擔保(Hanle Promotion)。

1.3 标記-整理算法

複制算法在對象存活率較高時就要進行較多的複制操作,效率将會變低。

老年代一般不使用這種算法。

後續步驟不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的記憶體

1.4 分代收集算法

當代商業虛拟機的垃圾收集算法 都采用“分代收集” 算法。根據對象存活周期的不同将記憶體劃分為幾塊,一般是把java堆分為新生代和老年代。

新生代中,每次垃圾收集時都發現有大批對象死去,隻有少量存活,那就選用複制算法;

老年代中因為對象存活率高、沒有額外空間對他進行配置設定擔保,必須使用“标記-清理”或"标記-整理"算法進行回收。

2.HotSpot算法實作

2.1 枚舉根節點

GC停頓 stop the world

oopMap

2.2 安全點 Safe Point

搶占式中斷:不需要線程的代碼主動去配合,在GC發生時,首先把所有線程全部中斷,如果發現有線程中斷的地方不在安全點上,就恢複線程,讓她跑到安全點上 。現在幾乎沒有虛拟機實作采用搶先是中斷來暫停線程進而響應GC事件。

主動式中斷:當GC需要中斷線程時,不直接ui線程操作,僅僅簡單的設定一個标志。各個線程執行時主動去輪詢這個标志,發現中斷标志為真是就自己中斷挂起。輪詢标志的地方和安全點是重合的。

2.3 安全區域 safe Region

一段代碼片段之中,引用關系不會發生變化。在這個區域中額任意地方開始GC都是安全的。

線上程執行到 Safe Region的代碼時,首先辨別自己已經進入Safe Region,那樣當在這段時間裡JVM要發起gc時,就不用管辨別自己為Safe Region狀态的線程了,線上程要離開Safe Region時,他要檢查系統是否已經完成了根節點枚舉,或者是整個GC過程,如果完成了,那線程就繼續執行,否則他就必須等待直到收到可以安全離開Safe Region的信号為止。

3.垃圾收集器

3.1 Serial 收集器 單線程收集器

隻會使用一個cpu或一條手機線程去完成垃圾收集工作;

在進行垃圾收集時,必須暫停其他所有額工作線程,直到他收集結束。這項工作實際上是由虛拟機在背景Z自動發起和自動完成的,在使用者不可見額情況下吧使用者正常工作的線程全部停掉。

虛拟機運作在client模式下額預設新生代收集器/

3.2 ParNew收集器

Serial收集器的多線程版本。

除了Serial外,隻有ParNew能與CMS收集器配合使用

3.3 Parallel Scavenge 收集器

新生代收集器,算法:複制算法 并行的多線程收集器。

關注點不同:

CMS等收集器關注點:盡可能縮短垃圾收集時使用者線程的停頓時間。

Parallel Scavenge收集器關注點:達到一個可控制的吞吐量。

吞吐量:CPU用于運作代碼的時間與CPU總消耗時間的比值。

停頓時間越短就越适合需要與使用者互動的程式,良好的響應速度能提升使用者體驗。

高吞吐量可以高效的利用CPU時間,盡快完成程式的運算任務,主要适合在背景運算而不需要太多互動的任務。

控制吞吐量的參數:

-XX:MaxGCPauseMills: 控制最大垃圾收集停頓時間。 GC停頓時間縮短是以犧牲吞吐量和新生代空間換取的。

-XX:GCTimeRatio:直接設定吞吐量大小。垃圾收集時間占總時間的比率,相當于吞吐量的倒數。

是以,Parallel Scavenge也經常被稱為“吞吐量優先”的收集器。

GC自适應的調節政策:

Parallel Scavenge收集器有一個參數-XX:UseAdaptiveSivePolicy,是開關參數,打開之後,就不需要手工指定新生代的大小(-Xmn),Eden與Survivor的比例(-XX:SurvivorRatio)、晉升老年代對象大小(-XX:PretenureSizeThreshold)等細節參數了。虛拟機會根據目前系統的運作情況收集性能監控資訊,動态調整這些參數以提供最合适的停頓時間或者最大的吞吐量。

《深入了解java虛拟機 JVM進階特性與最佳實踐》 p80

3.4 Serial Old收集器

Serial Old是Serial收集器的老年代版本,是一個單線程收集器。使用“标記-整理”算法。

意義在于:給Client模式下的虛拟機使用。

在Server模式下的兩大用途:1.在jdk1.5以及之前的版本中與Parallel Scavenge收集器搭配使用

2.作為CMS收集器的後備預案,在并發收集發生Concurrent Mode Failure時使用。

3.4 Parallel Old收集器

Parallel Old是Parallel Scavenge收集器的老年代版本。使用多線程和“标記-整理”算法

jdk1.6以後才開始使用。

在此之前,新生代的Parallel Scavenge和老年代Serial Old配置使用外别無選擇(因為Parallel Scavenge無法與CMS配合工作),由于老年代Serial Old在服務端性能上的拖累,單線程的老年代手機無法充分利用伺服器多CPU的處理能力,吞吐量甚至不如ParNew + CMS組合“給力”。

Parallel Old收集器出現後,“吞吐量優先”收集器終于有了比較名副其實的應用組合,在注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge + Parallel Old收集器。

3.4 CMS收集器

(Concurrent Mark Sweep)收集器是一種以擷取最短回收停頓時間為目标的收集器。

适合 重視服務的響應速度,希望停頓時間最短的網際網路站或者B/S系統的服務端 的應用的需求。

步驟:

初始标記 - 标記一下GC Roots能直接關聯到的對象,速度很快。

并發标記 - GC Roots Tracing,可與使用者線程同時工作。

重新标記 - 修正并發标記期間因使用者程式繼續運作而導緻标記産生變動的那一部分對象的标記記錄。時間比初始标記長,但比并發标記短。

并發清除 - 可與使用者線程同時工作。

整個過程耗時最長的并發标記和并發清除過程收集器線程都可以與使用者線程一起工作,是以總體上說,CMS收集器的記憶體回收過程始于使用者線程一起并發執行的。

主要有點已經在名字中展現出來了:并發收集、低停頓。,一些文檔中也稱之為并發低停頓收集器(Concurrent Low Pause Collector)。

有以下三個缺點:

1.CMS收集器對CPU資源非常敏感,因為占用了一部分線程。

2.CMS收集器無法處理浮動垃圾,肯惡搞出現“Concurrent Mode Failure”失敗而導緻另一次Full GC的産生。

3.CMS是一款基于“标記清除”算法實作的收集器,收集結束會有大量空間碎片産生。老年代空間剩餘很大,但無法找到足夠大的連續空間來配置設定目前對象,不得不提前觸發一次Full GC。

-XX:+UseCMSCompactAtFullCollection開關參數:預設開啟。用于在CMS收集器頂不住要繼續甯Full GC開啟時記憶體碎片的合并整理過程,記憶體整理的過程是無法并發的,空間碎片問題沒有了,但停頓時間不得不變長。

-XX:CMSFullGCsBeforeCompaction,用于設定執行多少次不壓縮的Full GC後,跟着來一次帶壓縮的(預設值為0,表示每次進入Full GC時都進行碎片整理)

3.5 G1收集器

Garbage-First G1收集器,

特點:并行與并發、分代收集、空間整合(整體”标記-整理“,局部”複制“,可預測的停頓)

避免在整個java堆中繼續甯全區域的垃圾收集,G1跟蹤各個Region裡面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經驗值),在背景維護一個優先清單,每次根據允許的收集時間,優先回收價值最大的Region。 這種使用Region劃分記憶體空間以及有優先級的區域回收方式,保證了G1收集器在有限的時間内可以擷取盡可能高的收集效率。

步驟:

初始标記- 标記一下GC Roots能直接關聯到的對象,并且修改TAMS(Next Top at Mark Start)的值,讓下一階段使用者程式并發運作時,能在正确可用的Region中建立新對象,這階段需要停頓線程。但耗時很短。,

并發标記 - 從GC Roots開始對堆中對象進行可達性分析,找到存活的對象,耗時較長,但可與使用者線程并發執行。

最終标記 - 為了修正在并發标記期間因使用者程式繼續運作二導緻标記産生變動的那一部分标記記錄-》Remeber Set Logs -》Rememberd Set。 需要停頓線程,但是可并行執行。

篩選回收 - 首先對各個Region的回收價值和成本繼續甯排序,根據使用者所期望的GC停頓時間來指定回收計劃。

3.6 記憶體配置設定與回收政策

自動記憶體管理:給對象配置設定記憶體 、 回收配置設定給對象的記憶體。

對象的記憶體配置設定,即在堆上配置設定,對象主要配置設定在新生代的Eden區上,如果i啟動了本地線程配置設定緩沖,将按線程優先在TLAB上配置設定。 少數情況也可能直接配置設定在老年代,配置設定的規則不是百分之百固定的。其細節取決于目前使用的是哪一種垃圾收集器組合,還有虛拟機中與記憶體相關的參數的設定。

3.6.1 對象優先在Eden配置設定。

package GCTest; public class GcTestOne { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testAllocation(); } public static void testAllocation() { byte[] allocation1, allocation2, allocation3, allocation4; allocation1 = new byte[2 * _1MB]; allocation2 = new byte[2 * _1MB]; allocation3 = new byte[2 * _1MB]; allocation4 = new byte[4 * _1MB]; } }

運作結果

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=58567:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.GcTestOne [GC (Allocation Failure) [PSYoungGen: 6248K->776K(9216K)] 6248K->4880K(19456K), 0.0030607 secs] [Times: user=0.02 sys=0.02, real=0.00 secs] Heap PSYoungGen total 9216K, used 7157K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 77% used [0x00000000ff600000,0x00000000ffc3b5f8,0x00000000ffe00000) from space 1024K, 75% used [0x00000000ffe00000,0x00000000ffec2020,0x00000000fff00000) to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) ParOldGen total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

新生代 6248 變為776kb。總記憶體沒有變化9216kb,因為三個對象是存活的,虛拟機沒有找到可回收的對象。

GC發生的原因是,給4配置設定記憶體的收,發現Eden已經被占用了6MB,剩餘空間已經不足以配置設定4所需的4MB記憶體,是以發生MinorGC,GC期間虛拟機又發現已有的3個3MB的對象全部無法放入Survivor空間,(Survivor空間隻有1MB左右),是以通過配置設定擔保機制提前轉移到老年代去。

(GC日志與原書中不一緻,是由于JDK版本不一緻,應該是這樣的。嗯)

3.6.2 大對象直接進入老年代。(大對象:需要大量連續記憶體空間的java對象,最典型的大對象就是那種很長的字元串以及數組, 大對象對虛拟機的記憶體配置設定來說就是一個壞消息,,更壞的是遇到一群”朝生夕滅“的大對象,經常出現大對象容易導緻記憶體還有不少空間時就提前觸發垃圾收集以擷取足夠的空間來”安置“他們)。

虛拟機提供了一個-XX:PretenureSizeThreshold參數,令大于這個設定值的對象直接在老年代配置設定。這樣做的目的是避免在Eden區及兩個Survivor區之間發生大量的内容複制。(新生代采用複制算法收集記憶體)

package GCTest; public class BigObject { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testPretenureSize(); } private static void testPretenureSize() { byte[] allocation; allocation = new byte[4 * _1MB]; } }

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728 "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=58221:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.BigObject Heap PSYoungGen total 9216K, used 6412K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc43128,0x00000000ffe00000) from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) ParOldGen total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

上述執行結果與《深入了解java虛拟機》原書不同,因為該參數隻針對Serial和ParNew兩款收集器。Parallel Scavenge不認識這個參數。

通過在cmd執行java -XX:+PrintCommandLineFlags -version,

《深入了解java虛拟機-JVM進階特性與最佳實踐》讀書筆記 垃圾收集器與記憶體配置設定政策
《深入了解java虛拟機-JVM進階特性與最佳實踐》讀書筆記 垃圾收集器與記憶體配置設定政策

3.6.3 長期存活的對象将進入老年代。

如果對象在Eden出生并經過一次Minor GC後仍然存活,并且能被Survivor容納的話,将被移動到Survivor空間中,并且對象年齡設為1.。對象在Survivor區中每”熬過“一次Minor GC,年齡就增加1歲,當他的年齡增加到一定程度(預設15歲),将會被晉升到老年代。 門檻值設定:-XX:MaxTenuringThreshold。

package GCTest; public class TenuringThreshold { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { testTenuringThreold(); } @SuppressWarnings("unused") private static void testTenuringThreold() { byte[] allocation1, allocation2, allocation3; allocation1 = new byte[_1MB / 4]; // 什麼時候進入老年代取決于XX:MaxTenuringThreshold設定 allocation2 = new byte[4 * _1MB]; allocation3 = new byte[4 * _1MB]; allocation3 = null; allocation3 = new byte[4 * _1MB]; } }

"D:\Program Files\java\jdk1.8\bin\java.exe" -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution "-javaagent:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\lib\idea_rt.jar=51973:D:\codeSoftWare\idea\IntelliJ IDEA 2019.2.1\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\java\jdk1.8\jre\lib\charsets.jar;D:\Program Files\java\jdk1.8\jre\lib\deploy.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\access-bridge-64.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\cldrdata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\dnsns.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jaccess.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\jfxrt.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\localedata.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\nashorn.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunec.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunjce_provider.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunmscapi.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\sunpkcs11.jar;D:\Program Files\java\jdk1.8\jre\lib\ext\zipfs.jar;D:\Program Files\java\jdk1.8\jre\lib\javaws.jar;D:\Program Files\java\jdk1.8\jre\lib\jce.jar;D:\Program Files\java\jdk1.8\jre\lib\jfr.jar;D:\Program Files\java\jdk1.8\jre\lib\jfxswt.jar;D:\Program Files\java\jdk1.8\jre\lib\jsse.jar;D:\Program Files\java\jdk1.8\jre\lib\management-agent.jar;D:\Program Files\java\jdk1.8\jre\lib\plugin.jar;D:\Program Files\java\jdk1.8\jre\lib\resources.jar;D:\Program Files\java\jdk1.8\jre\lib\rt.jar;E:\coding\Practice\out\production\Practice;E:\coding\Practice\lib\asm-5.0.3.jar;E:\coding\Practice\lib\cglib-2.2.jar;E:\coding\Practice\lib\asm-all-7.0.1.jar;E:\coding\Practice\lib\asm-tree-5.0.3.jar;E:\coding\Practice\lib\cglib-nodep-3.2.4.jar;E:\coding\Practice\lib\asm-analysis-5.0.3.jar" GCTest.TenuringThreshold Heap PSYoungGen total 9216K, used 6668K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000) eden space 8192K, 81% used [0x00000000ff600000,0x00000000ffc83138,0x00000000ffe00000) from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000) to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000) ParOldGen total 10240K, used 8192K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000) object space 10240K, 80% used [0x00000000fec00000,0x00000000ff400020,0x00000000ff600000) Metaspace used 3448K, capacity 4496K, committed 4864K, reserved 1056768K class space used 376K, capacity 388K, committed 512K, reserved 1048576K Process finished with exit code 0

由于jdk1.8 perm 與1.6不同,是以PrintTenuringDistribution參數未起效。

3.6.4 動态對象年齡判定。

不一定對象年齡必須達到門檻值設定菜呢個晉升老年代,如果在Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象就可以直接進入老年代。

3.6.4 空間配置設定擔保

老年代的連續空間大于新生代對象總大小或者曆次晉升的平均大小就會進行Minor GC,否則将進行F ull GC。