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

对象在内存中的内存布局是什么样的?

时间:2023-04-02 10:36:49 Java

Java对象的存储结构。在Hotspot虚拟机中,对象在内存中的存储布局分为三个区域:对象头(Header)、实例数据(InstanceData)和对齐填充(Padding)。Java对象实例Hotspt采用OOP-Klass模型。它是描述java对象实例的模型,可以分为两部分:OOP(OrdinaryObjectPointer)是指普通对象指针,包括MarkWord和Klass指针。MarkWord用于存储当前对象运行时的一些状态数据;Klass指针指向Klass,用来告诉当前指针指向的对象的类型,即对象是用哪个类创建的。对象模型是因为hotspotjvm的设计者不希望每个对象都包含一个虚表(虚函数表),所以将对象模型拆分为klass和oop,其中oop不包含任何虚函数,klass包含virtualfunctionsTable,methoddispatch-objectheaderHotSpot虚拟机的对象头包括两部分信息:_mark:markOop第一部分_mark:markOop用于存放对象本身的运行时数据,比如哈希码(HashCode),GCscoreGenerationage,lockstatusflag,threadholdedlock,partialthreadID,parttimestamp等。这部分数据的长度在32位和64位虚拟机中分别为32bit和64bit(压缩指针为未开启)。正式名称是“MarkWord”_klass:klassOop对象头的另一部分是一个klass类型指针,即对象指向它。类元数据的指针,虚拟机通过这个指针来判断对象是哪个类实例的length如果是数组对象,对象头还有一段数据表示数组的长度,大小为32bit,4字节——对象的实际数据实例数据部分是对象实际存储的有效信息,也是程序代码中定义的各类字段的内容。无论是从父类继承还是在子类中定义,都需要记录下来。Alignmentpadding第三部分alignmentpadding不一定存在,也没有什么特殊意义,只是起到占位符的作用。因为HotSpotVM的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,换句话说,对象的大小必须是8字节的整数倍。对象头部分恰好是8字节的倍数(1或2倍),因此,当对象实例数据部分不对齐时,需要通过对齐填充来完成。简单的可以总结如下知道了这4部分之后,我们来验证一下底层。借助第三方包JOL=JavaObjectLayoutjava内存布局来看。简单几行代码就可以看到内存布局样式:org.openjdk.joljol-core0.9公共类JOLSampleDataModels{私有静态对象o;publicstaticvoidmain(String[]args){o=newObject();System.out.println(ClassLayout.parseInstance(o).toPrintable());System.out.println("==================加载锁后==================");同步(o){System.out.println(ClassLayout.parseInstance(o).toPrintable());}}}从输出结果来看:objectheader包含12个字节,分为3行,前2行其实是markwords,第三行是klass指针。值得注意的是,锁定前后输出从001变为000。Markword的用途:8字节(64bit)的header记录了一些信息,锁是修改markword的内容。8字节(64bit)的header记录了一些信息,lock就是修改markword的内容。64bit的header记录了一些信息信息。从001无锁状态到00轻量级锁状态。New产生一个object对象,占用16个字节。对象头占用12个字节。由于Object中没有额外的变量,instance=0。考虑到object的内存大小必须能被8字节整除,那么padding=4。最后,newObject()的内存大小为16字节。什么样的对象会扩展到老年代?在很多场景下,比如对象太大,可以直接进入,但是这里要讨论的是,为什么YoungGC出来的对象,最多在YoungGC存活后进入Old区15次(年龄可调,默认15次)。上图的热点标记中,用了4位来表示代际年龄,所以可以表示的最大范围是0-15。所以这就是为什么新生代的年龄不能设置超过15的原因。可以在工作中通过-XX:MaxTenuringThreshold来调整,但是一般我们不会动。【欢迎关注】:码农架构专注于系统架构、高可用、高性能、高并发技术分享