GC 常見問題
哪些情況新生代會進入老年代
- 新生代 GC 后幸存區(survivor)不夠存放存活下來的對象,會通過內存擔保機制晉升到老年代。
- 大對象直接進入老年代,因為大對象再新生代之間來會復制會影響 GC 性能。由
-XX:PretenureSizeThreshold=1048576
配置 - 長期存活的對象,比如經過了15次gc后還存活的對象,由
-XX:MaxTenuringThreshold=10
配置- 但是這個年齡是會動態調整的,每次新生代GC后,JVM都會動態調整這個閾值大小,調整的方式是,從年齡為1的所有對象向上累加,直到內存大小大于
-XX:TargetSurvivorRatio
(默認50%) - 例如總共有100MB新生代大小,閾值就是50MB,累加年齡為1的對象,此時10MB,累加年齡為2的對象,此時25MB,累加年齡為3的對象,此時45MB,累加年齡為4的對象,此時55MB>50MB,那么閾值就被設置成4,下次GC時年齡大于等于4的對象會晉升到老年代
- 為什么默認是15?
- 因為對象頭里有個age字段,占4個bit位,所以最大就是15,初始值設為最大,然后依靠后面動態調整。
- 那這樣的話,小于等于15都可以吧,反正有動態調整,為什么選15呢?
- 因為
-XX:MaxTenuringThreshold
其實是限定了一個動態調整年齡范圍的上限,設為15能讓動態調整更為靈活
- 因為
- 但是這個年齡是會動態調整的,每次新生代GC后,JVM都會動態調整這個閾值大小,調整的方式是,從年齡為1的所有對象向上累加,直到內存大小大于
什么時候 Full GC
- 調用
System.gc()
- 新生代對象晉升老年代時,老年代內存不足。此時觸發Full GC。
- 大對象分配到老年代時,老年代內存不足。此時觸發Full GC。
- 元空間內存不足,Full GC回收沒有使用的類(類沒有實例化對象)。
- CMS GC時有對象要放入老年代,老年代內存不足,報Concurrent Mode Failure 錯誤,并觸發 Full GC。
- G1 回收器回收速率跟不上對象分配速率,也會觸發 Full GC。
什么是 Concurrent Mode Failure?
- CMS收集器在工作時,因為用于線程和垃圾回收在并發標記和并發清除階段是并行的,此時老年代空間不足(例如浮動垃圾過多,用戶創建對象頻繁,新生代晉升老年代),就會出現Concurrent Mode Failure
- 出現Concurrent Mode Failure會怎樣?
- 觸發Full GC