1.首先,了解下什么是JVM报告?
2. 然后,看看如何设置控制台打印JVM报告?
复制-verbose:gc -XX:+PrintGCDetails到run configuration的VM options
3.接着,那这个报告里面到底有什么有价值的信息呢?
- 用了哪个垃圾回收器
- 新生代大小
- eden区大小和使用情况
- to survivor区大小和使用情况
- from survivor区大小和使用情况
- 老年代大小和使用情况
- minorGC和Full GC是否发生和发生具体情况
上面两张图没写的信息基本可以忽略
4. 最后,我们通过一个真实案例来解释上面的数据会不会更好理解呢?
首先创建JVMTest
代码如下,创建4个数组和进行一次full gc
public class JVMTest {
private static final int M = 1024 * 1024;
public static void main(String[] args) {
byte[] b1 = new byte[2 * M];
byte[] b2 = new byte[2 * M];
byte[] b3 = new byte[2 * M];
byte[] b4 = new byte[4 * M];
System.gc();
}
}
然后我们来设置一下JVM参数(为什么我要设置?因为刚开始学,写死这些参数,更方便我们观察)
-verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
解释下参数的意思:
// 打印堆信息
-verbose:gc -XX:+PrintGCDetails
// 指定堆内存的大小20M
-Xms20M -Xmx20M
// 指定新生代内存10M
-Xmn10M
// 指定Eden Survivor1,Survivor2之间内存比例为(8:1:1)
-XX:SurvivorRatio=8
现在新生代和老生代都是10M,而新生代里Eden8M,两个Surviror都是1M
接着执行我们的代码
看到了下图
JVM报告的意思是:
发生了两次GC,一次Minor GC,目前已使用内存为4M(4782k);发生了一次Full GC,目前已使用内存10M;
eden区一共8M,已使用61%即使用了4~5M
survivor区0%,原因是被gc了
the space老年区一共10M,使用了6M
接着我们从代码的角度解释为什么内存会这样分配:
public static void main(String[] args) {
byte[] b1 = new byte[2 * M];
byte[] b2 = new byte[2 * M];
byte[] b3 = new byte[2 * M];
byte[] b4 = new byte[4 * M];
System.gc();
}
首先创建了3次2m大小的数组,此时eden区一共8M大小,被使用了6M,接着b4创建一个4M大小的数组,eden区发现不够空间,执行一次minor GC,且根据“内存分配策略”,动态对象年龄判断:幸存区相同年龄对象的占幸存区空间的多于其一半,将进入老年代 ,所以此时这三个2M数组被划进老年区,老年区一共10M,此时变成6M,eden区清空,此时b4顺利存入eden区。
完~