垃圾回收日志与算法深度解读
經過前面對于JVM垃圾回收學習了純理論相關的東東,這次則要開始用代碼編寫大量的實驗來對理論進行佐證,下面開始,先在IntelliJ IDEA工程中新建一個全新的包:
然后新建一個類:
接下來則會編寫一個超級簡單的程序,程序雖簡單,但是通過增加一些JVM的參數可以用簡單的程序來闡述JVM垃圾回收的很多知識點,所以意義還是挺大的,具體如下:
哇,確實是簡單,但是這里有個注意點:就是對于這個byte類型的數組其實里面存放的是為0的原生類型,可以打印看一下:
而如果是引用類型的數組則里面每個存放的是null,需要明白,接下來多創建幾個byte數組:
目前來看這是一個非常非常之low的程序,但是如果咱們給JVM增加一些運行參數,再輸出看到的東東則會大不一樣,下面來增加一些啟動參數:
這里有意將堆空間設置得較小以便可以供咱們觀察GC的情況,繼續:
還有最后一個參數:
這代表啥意思呢?其實它代表新生代的比例,如之前理論所介紹:
也就是這里的配置就代表新生代的區域是8:1:1,也就是Eden空間和Survivor空間的占比是8:1。接下來咱們再來運行一下:
而這些信息的輸出其實是JVM的這個參數發揮著作用,如下:
不信咱們將這個參數去掉再來運行:
果真就木有了,所以還是將該參數加回來。其實目前沒有GC相關的日志出來,接下來再來創建一個新的字節數組:
再運行:
/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/bin/java -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/lib/tools.jar:/Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/mysql/mysql-connector-java/5.1.34/46deba4adbdb4967367b013cbc67b7f7373da60a/mysql-connector-java-5.1.34.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/cglib/cglib/3.2.0/bced5c83ed985c080a24dc5a42b0ca631556f413/cglib-3.2.0.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.ow2.asm/asm/5.0.3/dcc2193db20e19e1feca8b1240dbbc4e190824fa/asm-5.0.3.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant/1.9.4/6d473e8653d952045f550f4ef225a9591b79094a/ant-1.9.4.jar:/Users/xiongwei/.gradle/caches/modules-2/files-2.1/org.apache.ant/ant-launcher/1.9.4/334b62cb4be0432769679e8b94e83f8fd5ed395c/ant-launcher-1.9.4.jar com.jvm.gc.MyTest1 [GC (Allocation Failure) [PSYoungGen: 7167K->464K(9216K)] 7167K->6616K(19456K), 0.0060472 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] [Full GC (Ergonomics) [PSYoungGen: 464K->0K(9216K)] [ParOldGen: 6152K->6487K(10240K)] 6616K->6487K(19456K), [Metaspace: 2649K->2649K(1056768K)], 0.0048810 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] hello world HeapPSYoungGen total 9216K, used 2290K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)eden space 8192K, 27% used [0x00000007bf600000,0x00000007bf83c9a0,0x00000007bfe00000)from space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)to space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)ParOldGen total 10240K, used 6487K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)object space 10240K, 63% used [0x00000007bec00000,0x00000007bf255d40,0x00000007bf600000)Metaspace used 2656K, capacity 4486K, committed 4864K, reserved 1056768Kclass space used 287K, capacity 386K, committed 512K, reserved 1048576KProcess finished with exit code 0此時就出現了兩種類型的GC,說明發生了GC操作,而這兩種類型的GC其實在之前的理論學習中也提及過,回顧一下:
接下來咱們再來修改程序:
也就是說隨著我們創建的字節的多少,其GC的輸出也會不一樣,接下來則對這些日志輸出進行一個解答,了解它們能夠更加深刻的理論GC相關的東東:
其實圖中的疑問也來自于之前的理論學習,回顧下:
也就是說對于咱們的新生代是采用PS收集器來進行垃圾回收的,接著繼續往下分析:
但是!!我在配置的JVM參數新生代的容量其實設置的是10M,如下:
為啥我們在日志中看到的新生代總的容量只有9M呢?這里就還得回到新生代的空間組成了,它是由一個Eden空間和兩個Survivor空間組成的,其中Survivor只會用一個,另一個會是空間進行數據交換用的,所以其總的新生代的大小就是Eden空間(8M)+1個Survivor空間(1M) = 9M。繼續往下分析日志:
為啥總的堆大小的容量是19M,而非我們指定的20M呢?
還是因為年輕代總大小會少1M。往下繼續:
至此對于GC的日志就徹底了解了,對于FULL GC其實里面的含義也一樣,接下來則是整個垃圾回收的匯總信息,分析一下:
最后咱們來計算一下這個老年代已使用了8K是如何得出來的?
還得由之前的GC日志來得算,下面來算一下:
這倆一相減就得出在新生代進行了gc之后所釋放的容量為8191-464=7727,接著再來看一下總堆的釋放情況:
那有個疑問:為啥總的堆空間釋放的大小還不如新生代釋放的大小呢?這里需要注意:對于新生代的釋放其實分為兩種:一是真正的被回收的,二是沒有真正被回收,而是該對象進升到老年代了,而堆空間的釋放值代表是真正被釋放的大小。
那這倆數據之間有啥關系呢?其實這個關系是非常微妙的,為啥,看一下:“7727-7719=8k”,這不就是我們看到老年代已使用的大小么?
所以新生代釋放的大小-總堆釋放的大小則就是從新生代進升到老年代的容量大小。
總結
以上是生活随笔為你收集整理的垃圾回收日志与算法深度解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【人工智能】禅与计算机程序设计艺术评论:
- 下一篇: 朋友欠钱老拖着不给?这个小工具让他立马还