
GC流程是每一個Java開發人員都應該掌握的內容。你知道什么時候觸發Minor GC?什么時候觸發
Minor GC 的過程是怎么樣的?Full GC 的過程又是怎么樣的?這一切都要從「壓死駱駝的最后一根稻草」說起。
看圖,看圖,看圖。跟着我畫的流程圖走一遍,就清楚了!
擠滿新生代的最后一個對象
我們應當知道,新創建的對象一般會被分配在新生代中。常用的新生代的垃圾回收器是 ParNew 垃圾回收器,它按照 8:1:1 將新生代分成 Eden 區,以及兩個 Survivor 區。
某一時刻,我們創建的對象將 Eden 區全部擠滿,這個對象就是「擠滿新生代的最后一個對象」。此時,Minor GC 就觸發了。
正式 Minor GC 前的檢查
在正式 Minor GC 前,JVM 會先檢查新生代中對象,是比老年代中剩余空間大還是小。為什么要做這樣的檢查呢?原因很簡單,假如 Minor GC 之后 Survivor 區放不下剩余對象,這些對象就要進入到老年代,所以要提前檢查老年代是不是夠用。這樣就有兩種情況:
- 老年代剩余空間大於新生代中的對象大小,那就直接 Minor GC,GC 完 survivor 不夠放,老年代也絕對夠放
- 老年代剩余空間小於新生代中的對象大小,這個時候就要查看是否啟用了「老年代空間分配擔保規則」,具體來說就是看
-XX:-HandlePromotionFailure參數是否設置了(一般都會設置)
老年代空間分配擔保規則是這樣的。如果老年代中剩余空間大小,大於歷次 Minor GC 之后剩余對象的大小,那就允許進行 Minor GC。因為從概率上來說,以前的放的下,這次的也應該放的下。那就有兩種情況:
- 老年代中剩余空間大小,大於歷次 Minor GC 之后剩余對象的大小,進行 Minor GC
- 老年代中剩余空間大小,小於歷次 Minor GC 之后剩余對象的大小,進行 Full GC,把老年代空出來再檢查
Minor GC 后的處境
前面說了,開啟老年代空間分配擔保規則只能說是大概率上來說,Minor GC 剩余后的對象夠放到老年代,所以當然也會有萬一,Minor GC 后會有這樣三種情況:
- Minor GC 之后的對象足夠放到 Survivor 區,皆大歡喜,GC 結束
- Minor GC 之后的對象不夠放到 Survivor 區,接着進入到老年代,老年代能放下,那也可以,GC 結束
- Minor GC 之后的對象不夠放到 Survivor 區,老年代也放不下,那就只能 Full GC
實在不行只能 OOM
前面都是成功 GC 的例子,還有 3 中情況,會導致 GC 失敗,報 OOM:
- 緊接上一節 Full GC 之后,老年代任然放不下剩余對象,就只能 OOM
- 未開啟老年代分配擔保機制,且一次 Full GC 后,老年代任然放不下剩余對象,也只能 OOM
- 開啟老年代分配擔保機制,但是擔保不通過,一次 Full GC 后,老年代任然放不下剩余對象,也是能 OOM
