通過一些問題來討論 JVM 中年輕代和老年代的內容
- 為什么要區分年輕代和老年代?
- 哪些對像會進入老年代?
- 什么時候會進行年輕代GC?
- 什么時候會進行老年代GC?
1. 為什么要區分年輕代和老年代?
年輕代中的對象大部分都是短期存活的,老年代中的對象存活時間較長
而短期存活的對象,很快就會被垃圾回收線程回收。
考慮到兩部分對象的垃圾回收時機不同,所以就要將其區分
年輕代有年輕代的垃圾回收算法,老年代有老年代的垃圾回收算法,“因地制宜”
2. 哪些對象會進入老年代
我們分為 Young?GC 之前和 Young GC 來說
Young GC之前,如果加入堆內存的對象足夠大,則直接進入老年代,可通過?JVM 參數?“-XX:PretenureSizeThreshold” 來設置這個值,單位是字節
比如 “-XX:PretenureSizeThreshold” 的值設為 “1048576” 字節,而你創建了一個大小大于這個數的對象,比如一個超大的數組,此時就直接將這個大對象放到老年代里去
Young GC 之后,則有多種情況
如果對象已經經歷了15次 GC,即對象年齡已經達到 15,則會被轉移到老年代
還有一種動態對象年齡判斷,不需要對象年齡達到 15 也可以進入老年代。大致規則就是,假設當前放對象的 Survivor 區中,有一批對象的總大小大于了這塊區域的 50%,則所有年齡大于等于這批對象年齡的對象,都可以直接進入老年代
無論是年齡大于 15,還是動態對象年齡判斷,都是為了那些可以長期存活的對象盡早地進入到老年代
還有,如果 GC 過后,存活對象的大小大于 Survivor 可用空間,則這些對象也會直接進入到老年代?
3. 什么時候會進行年輕代?GC
這里年輕代 GC,認為是 Young GC
當年輕代中的 Eden 區中區域不夠用時,則會觸發年輕代 GC
4. 什么時候會進行老年代 GC
這里老年代 GC,認為是 Full GC?
每一次 Minor GC 之前,會檢查老年代老年代可用空間是否大于年輕代所有對象大小,因為可能 GC 之后,所有的年輕代對象都存活下來了。如果小于的話,則還要判斷是否打開了 "-XX:-HandlePromotionFailure"的參數設置
如果沒打開這個參數,則直接進行 Full GC
否則打開了的話, 則就看老年代內存大小,是否大于之前每一次 Minor GC 后進入老年代對象的平均大小。小于的話,則會進行 Full GC
這是 Minor GC 之前做的判斷。
如果 Minor GC 之后,存活對象大小大于 Survivor 可用空間,也大于老年代可用空間,也會進行 Full GC