JVM学习-深入理解Java虚拟机代码实践问题

本文探讨了《深入理解Java虚拟机》中关于MinorGC的案例在JDK1.8下的验证过程,分析了由于默认垃圾收集器、对象晋升规则及初始化对象影响测试结果的情况。通过调整VM参数和使用visualvm工具进行动态观察,最终发现初始化对象导致提前触发MinorGC。通过调用System.gc()解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《深入理解java虚拟机》第3版

代码清单3-7 新生代Minor GC

private static final int _1MB = 1024 * 1024;
/**
* VM参数: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
*/
public static void testAllocation() {
    byte[] allocation1, allocation2, allocation3, allocation4;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    allocation4 = new byte[4 * _1MB]; // 出现一次Minor GC
}

使用JDK1.8做验证,发现和书中描述不一致。

 

考虑前面版本成书较早,可能基于较早的jre版本运行。

首先考虑的原因是默认的垃圾收集器不同,JDK8默认为Parallel Scavenge+Parall Old组合 跟作者的JDK6使用的Serial+Serial Old组合的算法不一致。

因此增加参数:-XX:+UseSerialGC 后再次测试,还是相同结果。

然后想到新生代对象晋升老年代的规则之一:大对象直接分配到老年代。

因此增加参数:-XX:PretenureSizeThreshold=10485760 后测试,还是没有达到预期。

后来想到,老年代的4M不一定就是一个对象的4M,也可能是2个2M的对象。于是想到通过打断点运行,并配合可视化工具 visualvm 来动态观察JVM堆内存各区的变化情况。

 通过分析知道,JVM初始化时有部分对象影响了测试结果。即初始化时对象大小超过2M,到运行allocation1、allocation2后,在allocation3对象分配时Eden区已经不够存放,因此在预期之前发生了MinorGC。因此在运行目标代码前增加一行

System.gc();

解决了困惑。

 可能有人会问,原来那个正好40%,即4M,而我这边断点之后其实不是4M,而是6M+?这个猜测是因为断点导致一些对象被引用着而存活下来了,而不打断点运行时直接被当垃圾回收了。

结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值