当前位置: 首页 > 网络应用技术

Java中的对象内存布局以及如何计算对象的大小

时间:2023-03-06 16:42:07 网络应用技术

  在热点虚拟机中,内存中对象的布局可以分为3个区域:对象头(标题),实例数据和填充。

  如果对象是数组类型,则热点虚拟机使用3个单词宽度(Word)来存储对象头。如果对象是非阵列类型,则将对象标头用2个字宽。在32 -bit虚拟机中,1个单词宽度等于4个字节,即32位;在64位虚拟机中,1个单词宽度等于8个字节,即64位。

  热点虚拟机的一般对象标头包括信息的两个部分:“标记字”和“类指针”。数组对象还包括“数组长度”。

  32/64bit标记字主要用于表示对象的线程锁定状态。此外,它可用于与存储对象并存储对象的哈希码合作。32/64BitClass指针(klass)存储指针到对象类信息意味着对象可以知道该类型的类型类型的类型任何时间。64 -bit JVM打开指针时,压缩时为32位。32/64BitArray长度阵列的长度(仅当当前对象在当前对象为array时存在)。64 -bit JVM打开指针为32bit当压缩时,它用于存储对象本身的数据,例如hashcode,gc衰老,锁定状态徽标,线程锁紧,偏置线程ID,有偏见的时间戳等。64 -PIT虚拟机为32bit和64bit, 分别。

  当需要存储对象时,有很多数据。实际上,可以通过32位和64位位图结构记录的极限,但是对象标头信息是与对象本身定义的数据无关的额外存储成本。考虑到虚拟机的空间效率,虚拟Machinemark Word的空间效率被设计为一种非固定数据结构,以将尽可能多的信息存储在小空间中。它将根据对象的状态重复使用其存储空间,即不同的数据存储不同的数据。

  Java对象,年龄和锁定时间表中的标记单词中的哈希尺寸。在本文中,对标记单词的更详细说明和与同步的关系具有详细的解释:Java中同步的基本实现原则以及锁定升级优化的详细说明。

  在操作过程中,存储在标记字中的数据将随着锁定位置的更改而变化。32在虚拟机的不同状态下,标记字可能由下表组成:

  对象哈希代码,对象划分年龄(0)01解锁(锁定状态)偏向线程ID,偏差时间戳,对象代理年龄(1)01可以偏见(偏置锁)指向线程锁定记录(锁定记录))诗歌00轻质锁定点指向重量级锁(相互铃声)诗10重量锁定(CMS垃圾收集器使用的标记信息,其他时刻是空的)11GC标记类指针,目标头的另一部分是目标头是目标头是目标头是对象头的一部分是Typy Pointer的一部分,即,对象指向其元数据的指针,虚拟机确定该对象的哪个类是。并非所有虚拟机实现都必须保留对象数据上的类型指针。

  数据的这一部分的长度为32位,32位和64位虚拟机中的长度为64位。

  您可以使用-xx:+useCompressedClassPointers参数来压缩64位虚拟机的类型指针,压缩后的长度为32位。

  如果对象是Java数组,则必须有一个数据来记录对象头中数组的长度,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是,从阵列的元数据大小的数组的元数据中无法确定。

  数据的这一部分的长度为32位,32位和64位虚拟机中的长度为64位。

  您可以使用-XX:+ UseCompressedOOPS参数来压缩64位虚拟机。压缩后,64位虚拟机的长度为32位。

  实例数据部分是对象存储的有效信息,它也是程序代码中定义的各种字段内容。无论是从父类继承还是在子类中定义,都需要记录下来。

  该部分的存储序列将受到Java源中字段sallocrationSles和字段的定义顺序的影响。

  热点虚拟机的默认分配策略是长/double,int/float,short/char,byte/boolean,oop(可以压缩的普通对象指针)。可以从相同宽度字段的分布策略中看到它此外,使用内存重量排序优化空间的使用,也就是说,如果对象头占据12bytes,则它将选择小于4比或等于4bytes的类型。

  在基本类型和参考类型指针之间,有4个比值作为步长填充,当实例数据填充时,最后,将8比对齐为一个步骤。

  在满足上述先决条件的情况下,父类中定义的变量将出现在子类的前方。。

  对齐填充不一定存在,也没有特殊的含义。它仅在占用一点方面起作用,主要利用身体来提高阅读效率。由于热点VM的自动内存管理系统要求对象的起始地址必须是8个字节的整数倍数。换句话说,对象的大小必须是8个字节的整数倍数。对象的标题正是8字节的倍数(1次或两次)。因此,当对象的实例数据部分不对齐时,有必要通过对齐方式填充它。

  对象o = new Object()在内存中占16个字节(打开压缩),其中最后4个都是 - 在 - 对齐填充;

  通常,64位-BIT JVM的内存消耗是32位的1.5倍,因为对象指针在64-位架构下会加倍(宽度)。,记忆需求的突然增加可能会崩溃。

  从JDK 6 Update14开始,64位JVM正式支持-XX:+usecompressedoops参数和-xx:+usecompressedClassPointers参数可以压缩指针的大小和保存内存占用。查看默认情况下是否打开(默认情况下JDK6打开后)。

  在上述两种压缩策略中可以计算四个组合:

  

  但是,当使用第四个开放策略时,会出现警告:

  Java热点(TM)64位服务器VM警告:UseCompressedClassPointers RequreSteToOps

  这是因为JVM的限制:

  

  让我们看一下特定压缩和非压缩的比较:

  以下是64位虚拟机压缩的数据比较形式,没有压缩:

  Boolean11byte11short22Char22Char244Float4Long88Double8Reference84普通头1612阵列标头2416JOL,即Java对象布局。这是由OpenJDK提供的工具包。它可以帮助我们计算某个对象的内存布局和对象的大小。

  JOL简介:http://openjdk.java.net/projects/code-tools/jol//

  Maven依赖:

  首先检查JVM的基本信息:

  我的计算机输出如下:

  解释:

  第二行:指示启用了一般对象指针压缩,即-xx:+usecompressedoops。第三行:指示启用了类型指针压缩,即-xx:+usecompressedclasspointers以打开参数。第四行:对象的大小必须与8个字节对齐。第五行:指示字段类型的长度(字节),依次,参考句柄(对象指针),字节,布尔,布尔,char,short,short,int,float,float,float,double,长类型。线6:阵列类型(字节)的长度依次是参考句柄(对象指针),字节,布尔值,char,short,short,int,int,float,float,double,double类型。

  检查对象对象的内存布局。这是一个经典的Java访谈问题:新对象()的大小是多少?

  输出如下:

  首先解释相应术语的含义:

  接下来,查看对象对象的特定布局和大小:

  综上所述:

  对象对象占据了16比的内存大小,由两个部分组成:12 bytes的对象头和4个比对对齐。

  对象对象头由两个部分组成:8 Bytes的标记字+4 Bytes类指针。实例数据部分为0bytes。

  对象有多少个字节?实际上,它仍然是16个字节,但是目前还没有4个字节充满对齐。

  此外,数组的内存大小必须以数组的大小(压缩)和内部数组元素的指针大小(可以压缩参考类型指针)计算。

  这里的布局顺序主要是实例数据布局的顺序。该部分的存储顺序将受到Java源中虚拟机分配策略参数和字段的定义的影响。

  热点虚拟机的默认分配策略是长/double,int/float,short/char,byte/boolean,oop(普通对象指针)。参考,使用内存权重排序优化空间,即,如果对象头占12比特,则选择小于4bytes或等于4Byte的类型。

  在基本类型和参考类型指针之间,当填充实例数据时,用4个字节填充了4个字节,而最后,还有另一个时间将其填充为8 bytes。

  在满足上述先决条件的情况下,父类中定义的变量将出现在子类的前方。。

  测试案例如下:

  该计算机的测试结果如下,最后占据了72 bytes。你猜对了吗?

  建立对象是使用对象。我们的Java程序需要通过堆栈上的参考数据在堆栈上操作特定对象。由于参考类型仅指定对Java虚拟机规范中对象的参考,因此它不能定义应通过该参考来通过对象在访问堆中的特定位置并确定它。

  目前,主流访问方法是两种类型:句柄和直接指针。

  如果使用手柄访问,则将一块内存分为Java桩中的手柄池。对象的句柄地址存储在引用中,并且该句柄包含对象实例数据和类型数据的特定地址信息。

  如下所示:

  如果您使用直接指针访问,则Java Pile对象的布局必须考虑如何放置访问类型数据的相关信息,并且直接对象地址存储在参考中。在这个timemiddle。

  如下所示:

  这两个访问对象具有自己的优势。使用手柄访问的最大好处是稳定的手柄地址存储在参考中。实例数据指针,并且参考本身无需修改。

  使用直接指针访问方法的最大好处是它更快。它节省了指针定位的时间开销。由于对象在Java中的访问非常频繁,因此此类开销也是执行成本的巨大成本。EssencetheHotspot Virtual Machine使用直接指针来访问对象,但是从整个软件开发范围的角度来看,各种语言和框架的情况非常普遍。