深入浅出JVM-GC过程
深入淺出JVM-GC過程
- Minor GC
- 對象進入老年代的4種情況
- Full GC
- 空間分配擔保
Minor GC
- Minor GC過程
假設現在Heap內存大小為20M,其中年輕代為10M,老年代為10M,年輕代中Eden區6M,From區2M,To區2M,新創建的對象首先往Eden區分配,當再次分配一個對象,假設大小為1M,此時Eden區已經沒有足夠空間來給這個對象分配內存,如圖所示:
這時候觸發一次Minor GC,把Eden區的存活對象轉移到From區,非存活對象進行清理,然后給新創建的對象分配空間,存入Eden區
隨著分配對象的增多,Eden區的空間又不足了:
這時候再觸發一次Minor GC,清理掉Eden區和S1區的死亡對象,把存活對象轉移到S2區,然后再給新對象分配內存:
From區和To區是相對的關系,哪個區中有對象,哪個區就是From區,比如,再進行一次Minor GC,會把存活對象轉移到S1區,再為轉移之前,S2區是From區,S1區是To區,轉移后,S2區中沒有存活對象,變為To區,而S1區變為From區:
對象進入老年代的4種情況
假如進行Minor GC時發現,存活的對象在ToSpace區中存不下,那么把存活的對象存入老年代
大對象直接進入老年代
假設新創建的對象很大,比如為5M(這個值可以通過PretenureSizeThreshold這個參數進行設置,默認3M),那么即使Eden區有足夠的空間來存放,也不會存放在Eden區,而是直接存入老年代
長期存活的對象將進入老年代
此外,如果對象在Eden出生并且經過1次Minor GC后仍然存活,并且能被To區容納,那么將被移動到To區,并且把對象的年齡設置為1,對象沒"熬過"一次Minor GC(沒有被回收,也沒有因為To區沒有空間而被移動到老年代中),年齡就增加一歲,當它的年齡增加到一定程度(默認15歲,配置參數-XX:MaxTenuringThreshold),就會被晉升到老年代中
動態對象年齡判定
還有一種情況,如果在From空間中,相同年齡所有對象的大小總和大于From和To空間總和的一半,那么年齡大于等于該年齡的對象就會被移動到老年代,而不用等到15歲(默認):
Full GC
如果某個(些)對象(原來在內存中存活的對象或者新創建的對象)由于以上原因需要被移動到老年代中,而老年代中沒有足夠空間容納這個(些)對象,那么會觸發一次Full GC,Full GC會對整個Heap進行一次GC,如果Full GC后還有無法給新創建的對象分配內存,或者無法移動那些需要進入老年代中的對象,那么JVM拋出OutOfMemoryError
空間分配擔保
在發生Minor GC之前,虛擬機會先檢查老年代最大可用的連續空間是否大于新生代所有對象總空間,如果這個條件成立,那么Minor GC可以確保是安全的。如果不成立,則虛擬機會查看HandlerPromotionFailure這個參數設置的值(true或flase)是否允許擔保失敗(如果這個值為true,代表著JVM說,我允許在這種條件下嘗試執行Minor GC,出了事我負責)。如果允許,那么會繼續檢查老年代最大可用的連續空間是否大于歷次晉升到老年代對象的平均大小,如果大于,將嘗試進行一次Minor GC,盡管這次Minor GC是有風險的;如果小于,或者HandlerPromotionFailure為false,那么這次Minor GC將升級為Full GC
如果老年代最大可用的連續空間大于歷次晉升到老年代對象的平均大小,那么在HandlerPromotionFailure為true的情況下,可以嘗試進行一次Minor GC,但這是有風險的,如果本次將要晉升到老年代的對象很多,那么Minor GC還是無法執行,此時還得改為Full GC。
HandlerPromotionFailure為true時,如果某次需要轉移到老年代中的對象確實很多,老年代無法容納,那么也會先嘗試進行一次Minor GC,Minor GC無法執行時再進行Full GC,這樣雖然繞了圈子,但我們還是建議把這個參數設置為true,因為我們要盡量避免Full GC。
總結
以上是生活随笔為你收集整理的深入浅出JVM-GC过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: webStorm 永久破解
- 下一篇: 初识-Android之智能短信项目相关技