当前位置: 首页 > 后端技术 > Java

一道阿里面试题:如何计算JAVA对象的大小?

时间:2023-04-01 21:22:33 Java

在做JVM内存调优的时候,我们不可避免的需要计算对象的大小。在计算一个对象的大小时,需要考虑它是普通对象还是数组对象,因为普通对象和数组对象的对象头是有些区别的。并且从JDK6开始,为了节省内存,提高运行效率,引入了一项新技术:指针压缩。这加剧了计算物体尺寸的难度。本文将深入分析如何计算对象大小,保证计算结果不比实际差一个字节。对象结构对象结构想必深入研究过JVM的人都知道。它分为三个部分:对象头、实例数据和对齐填充。对象头分为三部分:MarkWord、类型指针、数组长度。其实对象头还有第四部分,你目前看到的书籍和视频都没有提到。对象头还有一个对齐填充部分。这部分没有保证。只有当数组对象没有启用指针压缩时才会出现下一个。如果你迷茫了,那就继续往回看。指针压缩看这四个字是不是一串问号:这是什么?这是如何工作的?为什么说它节省内存呢?...让我们弄清楚这些问题。我们先达成一个概念上的共识:所有的对象都是8字节对齐的。现在我有3个对象:test1(16字节)、test2(32字节)和test3(24字节)。为了便于说明,如果这三个对象中没有其他对象,则它们的内存地址为:test1=0x00000000(0byte~16byte)test2=0x00010000(16byte~48byte)test3=0x00110000(48byte~72byte)有没有发现规律,所有对象指针的最后三位都是0,这就是指针压缩的实现原理。启用指针压缩后,JVM将截断对象指针的最后三位数字。如果test2=0x10000,指针使能后会变成test2=0x10。使用的时候补回最后三位0,即test2=0x10000。因为开启指针压缩后,对象指针变成了4字节(32位),加上3个补码,一共35位.即启用指针压缩后,一个对象指针所能表示的最大堆空间为2的35次方,即32G。读者能否思考一下?想扩大一个oop所能代表的堆空间怎么办?我们来看看四种情况下(普通对象-指针压缩关闭、普通对象-指针压缩打开、数组对象-指针压缩关闭、数组对象-指针压缩打开)下对象大小是如何计算的。建议读者编写类似的代码进行测试,以便更深入地理解。测试代码:packagecom.qimingnan.adjust;导入org.openjdk.jol.info.ClassLayout;公共类Test1{inta=10;整数b=20;静态int[]arr={0,1,2};publicstaticvoidmain(String[]args){Test1test1=newTest1();System.out.printf(ClassLayout.parseInstance(test1).toPrintable());System.out.printf(ClassLayout.parseInstance(arr).toPrintable());}}普通对象1.不启用指针压缩24B=8B(MarkWord)+8B(KClassPointer)+4B+4B2.启用指针压缩24B=8B(MarkWord)+4B(KClassPointer)+4B(inta)+4B(intb)+4B(Padding)arrayobject1.未启用指针压缩40B=8B(MarkWord)+8B(KClassPointer)+4B(arraylength)+4B(headerPadding)+12B(3ints)+4B(objectPadding)2.开启指针压缩32B=8B(MarkWord)+4B(KClassPointer)+4B(arraylength)+12B(3ints)+4B(objectPadding)如何计算大小对象大家都学会了吗?介绍一个工具,jol,做测试的时候可以用这个工具org.openjdk.joljol-core0.10本文的某些部分可能不太容易理解。读者如有疑问,留言提问,我会一一解答。以后我会为大家开设新的系列专栏《手写JVM》。如果您对此感兴趣,请关注我。