通过前面对于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”,这不就是咱们看到老年代已使用的大小么?
因此新生代释放的大小-总堆释放的大小则就是重新生代进升到老年代的容量大小。