一次MinorGC案例研究时,一个M对象进入年轻代时,发现年轻代无法放下该对象,于是触发MinorGC,之后年轻代内的数据全部进入了老年代,M对象才得以进入年轻代;
JDK版本:java version "1.8.0_191"
JVM参数:-XX:+UseSerialGC -Xmx20m -Xms20m -Xmn10m -XX:+PrintGCDetails -XX:MaxTenuringThreshold=15
代码如下:
package com.study.demo.gc;
public class MinorGC3 {
private static final int _1MB = 1024 * 1024;
//MaxTenuringThreshold分代年龄1到15
//-XX:+UseSerialGC -Xmx20m -Xms20m -Xmn10m -XX:+PrintGCDetails -XX:MaxTenuringThreshold=15
public static void main(String[] args) {
byte[] allocation1, allocation2, allocation3;
allocation1 = new byte[_1MB / 4];
allocation2 = new byte[4 * _1MB];
allocation3 = new byte[4 * _1MB];
allocation3 = null;
allocation3 = new byte[6 * _1MB];
}
}
运行结果 :
C:\Java\jdk1.8.0_191\bin\java.exe -XX:+UseSerialGC -Xmx20m -Xms20m -Xmn10m -XX:+PrintGCDetails -XX:MaxTenuringThreshold=15 "-javaagent:D:\idea\IntelliJ IDEA 2018.1.6\lib\idea_rt.jar=62091:D:\idea\IntelliJ IDEA 2018.1.6\bin" -Dfile.encoding=UTF-8 -classpath C:\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Java\jdk1.8.0_191\jre\lib\rt.jar;E:\idea_work_study\jvm_study\target\classes;E:\m2\cglib\cglib\2.2.2\cglib-2.2.2.jar;E:\m2\asm\asm\3.3.1\asm-3.3.1.jar com.study.demo.gc.MinorGC3
[GC (Allocation Failure) [DefNew: 5842K->845K(9216K), 0.0024170 secs] 5842K->4941K(19456K), 0.0024415 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew: 5023K->0K(9216K), 0.0008570 secs] 9119K->4937K(19456K), 0.0008703 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 6364K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 77% used [0x00000000fec00000, 0x00000000ff236e08, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400388, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4936K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 48% used [0x00000000ff600000, 0x00000000ffad2088, 0x00000000ffad2200, 0x0000000100000000)
Metaspace used 3104K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 337K, capacity 388K, committed 512K, reserved 1048576K
Process finished with exit code 0
分析:年轻代10M 能用的只有9M 老年代10M
1.allocation1 = new byte[_1MB / 4]; 256kb数据进入年轻代
2.allocation2 = new byte[4 * _1MB]; 4Mb数据进入年轻代
3.allocation3 = new byte[4 * _1MB]; 4Mb数据准备进入年轻代时,年轻代发现放不下,先MinorGC,发现4MB+256KB进入不了Survivor的from或者to区(from/to只有1MB),于是通过担保策略,将年轻代的数据全部放入老年代也就是4MB+256Kb的数据进入了老年代,这时候4MB的数据就可以进到年轻代了
4.allocation3 = new byte[6 * _1MB]; 6MB的数据准备进入年轻代,年轻代发现放不下,先MinorGC,清理原先的4MB,由于allocation3 = null,6MB的数据就能进来了。
总共两次MinorGC