叫練手把手教你讀JVM之GC資訊
案例
眾所周知,GC主要回收的是堆記憶體,堆記憶體中包含年輕代和老年代,年輕代分為Eden和Surivor,如下圖所示。我們用案例分析下堆的GC資訊【版本:HotSpot JDK1.8】。
/** * @author :jiaolian * @date :Created in 2021-03-15 15:02 * @description:新生代記憶體測試 * @modified By: * 公眾號:叫練 */ public class NewGenTest { public static void main(String[] args) { //每次在Eden申請1M空間 byte[] bytes = null; for (int i=0; i<5; i++) { bytes = new byte[1024*1024]; } } }
案例很簡單,for迴圈執行5次,每次在Eden申請1M空間,假設我們分配堆記憶體空間是20m,並列印GC詳細資訊,配置過程:-XX:+PrintGCDetails -Xmx20m。
- -XX:+PrintGCDetails:列印GC詳細資訊。
- -Xmx20m:分配最大堆記憶體空間是20m。
GC詳細分析
執行程式,IDEA控制檯列印結果如下:
- 第一句話:年輕代GC了一次,因為第五次迴圈,Eden滿了,年輕代記憶體約6M(6144K),Eden回收前約5M(5057K),回收後是489K,年輕代記憶體回收前約是5M,回收後約是2M(1783K),總堆記憶體大小約是20M(19968K),GC耗時0.0016002 secs。
- 第二句話:年輕代總記憶體約6M,使用約5M。
- 第三句話:eden空間總記憶體約5M(5632K),使用率是94%。
- 第四句話:from是512K,使用率是95%。
- 第五句話:老年代總空間約14M(13824K),使用了1294K,這個使用空間是因為程式在Eden申請1M空間,判斷空間不夠,就申請from或者to空間,發現只有512K,就觸發monitor GC,將1M記憶體申請在老年代。
- 第六句話:元空間記憶體。
- -Xms 初始堆大小,不夠時,會自動擴充套件,所以一般Xms空間和Xmx最大堆空間設定成一樣的。
上面程式不變,設定JVM引數,-XX:+PrintGCDetails -Xmx20m -Xms5m,執行程式,部分結果如下圖所示。
如上圖所示:初始化堆大小是5M,新生代記憶體一共發生了4次GC,從上圖可以分析,Eden只有1M多記憶體可以被申請,所以第二次for迴圈申請1M空間就觸發了GC,資料就被丟進老年代,連續3次後,GC堆的空間由5M變為了6M,說明初始化堆空間不夠使,可以自動擴充套件堆記憶體。
當然我們還可以通過-Xmn 設定年輕代大小。下面我們看看年輕代中,Eden和from/to區域怎麼劃分。
上面程式不變,設定JVM引數,-XX:+PrintGCDetails -Xmx20m -Xmn10m -XX:SurvivorRatio=2,執行程式,部分結果如下圖所示。
- -Xmn10m:設定新生代記憶體為10m。
- -XX:SurvivorRatio=2:設定新生代中eden和Survivor比例是2:1。
我們設定新生代是10M,這裡顯示新生代大小是7.5M(7680K),實際上from/to是有一塊空間是每次GC做交換的區域(方便垃圾回收),所以實際上7680K=5120+2560。5120/2560=2,也就是新生代和和Survivor空間比例。
另外還有:-XX:NewRatio:設定老年代和新生代比例,一般是1/3)。比如設定-XX:NewRatio=2 -XX:+PrintGCDetails -Xmx30m
那麼老年代空間是20M,新生代空間是10M。
總結
最後總結下:
- -XX:+PrintGCDetails:列印GC詳細資訊。
- -Xmx20m:分配最大堆記憶體空間是20m。
- -Xmn10m:設定新生代記憶體為10m。
- -XX:SurvivorRatio=2:設定新生代中eden和Survivor比例。
- -XX:NewRatio:設定老年代和新生代比例,一般是1/3)。
今天學習了JVM之GC資訊引數配置,寫的不全同時還有許多需要修正的地方,希望親們加以指正和點評,喜歡的請點贊加關注哦。點關注,不迷路,我是【叫練】公眾號,微訊號【jiaolian123abc】邊叫邊