《深入了解虚拟机》一书中关于对象优先在Eden分配的例子

文章讨论了在JDK7与JDK8中测试内存分配时观察到的垃圾收集(GC)行为差异。在特定的VM参数下,作者发现数组分配可能在预期之外触发MinorGC。主要关注点在于Eden区、Survivor区和老年代的空间占用,以及Java虚拟机启动时对内存的需求。文中还提出了main方法启动时虚拟机加载类和初始化可能占用Eden区空间的可能性。

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

之前读第二版的时候,当时测试的时候就发现结果与书中不一致,第二版基于JDK7 ,本人是JDK8,以下为书中的结果:

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
}


 本人在测试时发现的结果:

 一开始看到老年代占了40%,我以为数组4直接进入进入老年代,毕竟也算大对象,经过几次实验得出结论,在分配数组3时就已经触发GC了,老年代中的40%是数组1和数组2.

debug发现在分配数组3是就已经触发GC了

 此外 我们还可以更改数组1或数组4的大小进行验证 ,首先把4改为5MB,我们可以发现老年代中的大小并未改变,而E区的从78%->90%,验证了我们的结论。

 也可以改数组1、2的大小,老年代的占比就会发生改变,不在贴图,可自己验证。

 同时还有个问题  S1区的94%究竟放的是谁呢?数组的大小最低都是2MB,而S1区的空间只有1024K。同时S1区也是GC后存活的对象待的地方,那么它可能也就是引起提前GC的原因。

在我把里面所有的方法变量都注释后,还是会占28%的空间,

 一个可能的答案:仅供参考。

Java中的main方法本身并不会占用2MB大小的Eden区空间。然而,Java虚拟机在启动时需要对一些类进行加载和初始化,这些操作可能会占用一定的内存空间。

当我们在命令行中执行java命令来启动一个Java程序时,Java虚拟机会先创建一个进程,并为该进程分配一定的内存空间。其中,包括了用于存放程序代码和数据的堆内存(Heap)以及用于存储Java虚拟机本身运行所需数据的非堆内存(Non-Heap)。

在堆内存中,Java虚拟机会将内存划分为多个区域,其中包括了年轻代(Young Generation),年老代(Old Generation)等。年轻代又会被划分为Eden区、Survivor区1和Survivor区2。而在默认情况下,Java虚拟机会将Eden区的大小设置为2MB。

当我们执行java命令启动Java程序时,Java虚拟机会首先加载并初始化一些必要的类,例如java.lang.Object、java.lang.String等。这些类的大小通常较大,因此可能会占用一部分Eden区的空间。此外,Java虚拟机还会为线程、类加载器等对象分配一些内存空间,这也会占用一定的Eden区空间。

因此,尽管main方法本身并不会占用2MB大小的Eden区空间,但是Java虚拟机在启动时所做的一些操作可能会占用一部分内存空间,包括Eden区的空间。

有了解的朋友欢迎探讨。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值