垃圾回收日誌與算法深度解讀

通過前面對於JVM垃圾回收學習了純理論相關的東東,此次則要開始用代碼編寫大量的實驗來對理論進行佐證,下面開始,先在IntelliJ IDEA工程中新建一個全新的包:java

而後新建一個類:mysql

接下來則會編寫一個超級簡單的程序,程序雖簡單,可是經過增長一些JVM的參數能夠用簡單的程序來闡述JVM垃圾回收的不少知識點,因此意義仍是挺大的,具體以下:sql

哇,確實是簡單,可是這裏有個注意點:就是對於這個byte類型的數組其實裏面存放的是爲0的原生類型,能夠打印看一下:apache

而若是是引用類型的數組則裏面每一個存放的是null,須要明白,接下來多建立幾個byte數組:數組

目前來看這是一個很是很是之low的程序,可是若是我們給JVM增長一些運行參數,再輸出看到的東東則會大不同,下面來增長一些啓動參數:jvm

這裏有意將堆空間設置得較小以即可以供我們觀察GC的狀況,繼續:ide

還有最後一個參數:學習

這表明啥意思呢?其實它表明新生代的比例,如以前理論所介紹:gradle

也就是這裏的配置就表明新生代的區域是8:1:1,也就是Eden空間和Survivor空間的佔比是8:1。接下來我們再來運行一下:spa

而這些信息的輸出實際上是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
Heap
 PSYoungGen      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 1056768K
  class space    used 287K, capacity 386K, committed 512K, reserved 1048576K

Process 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」,這不就是咱們看到老年代已使用的大小麼?

因此新生代釋放的大小-總堆釋放的大小則就是重新生代進升到老年代的容量大小。

相關文章
相關標籤/搜索