在 hotspot 虚拟机中,对象在内存中布局可以被分为三部分:对象头/实例数据/补位数据。下面一张图是一个普通 java 对象和一个数组对象的结构组成:
Hotspt 采用了 OOP-Klass 模型。 它是描述 java 对象实例的模型,可分为两部分:
对象的模型如下:
volatile markOop _mark; //标识运行时数据
union _metadata {
Klass* _klass;
narrowKlass _compressed_klass;
} _metadata; //klass指针
对象头主要有两部分(数组对象有三组分)组成。 Markword, Klass 指针(数组对象的话,还有一个 length)。
标记字主要存储对象运行时的一部分数据。主要内容有 hashcode,GC 分代年龄,锁状态标志位,线程锁标记,偏向线程ID,偏向时间戳等。MarkWord 在32位和64位虚拟机上的大小分别位32bit 和 64bit,它的最后 2 bit 是锁标志位,用来标记当前对象的状态,具体如下:
状态 | 标志位 | 存储内容 |
---|---|---|
未锁定 | 01 | 对象哈希码/对象分代年龄 |
轻量级锁定 | 00 | 指向锁记录的指针 |
膨胀(重量级锁定) | 10 | 执行重量级锁定的锁指针 |
GC 标记 | 11 | 空(不需要记录信息) |
可偏向 | 01 | 偏向线程id, 偏向时间戳,对象分代年龄 |
32 位 vm 在不同状态下 Markword 结构如下:
Klass 主要指向对象所属的类信息(class metadata)。虚拟机使用它来确定当前对象属于哪个类。klass 包含类的元数据信息,像类的方法,常量池等。你可以把它当作 java 里的 java.lang.Class 对象
如果这个对象是数组类对象,那么如上图右侧所示,会在对象头里额外的添加一个记录数组长度的字段
这部分主要存储的是对象实际的数据
hotspot vm 的自动内存管理系统要求对象起始地址比必须位 8 字节的整数倍,即对象的大小必须是 8 字节的整数倍。而对象头部分正好是 8 字节的整数倍,因此,当对象实例数据部分没有对齐时,此时需要对齐填充来补齐
首先,对象头大小的确定
有很多中方法计算,这里我们使用 jol 进行计算
首先假设我们待计算的对象所属的 Class 结构如下:
public class JOLSample_10_DataModels {
/*
* This example shows the differences between the data models.
*
* First layout is the actual VM layout, the remaining three
* are simulations. You can see the reference sizes are different,
* depending on VM bitness or mode. The header sizes are also
* a bit different, see subsequent examples to understand why.
*/
public static void main(String[] args) throws Exception {
Layouter l;
l = new CurrentLayouter();
System.out.println("***** " + l);
System.out.println(ClassLayout.parseClass(A.class, l).toPrintable());
l = new HotSpotLayouter(new X86_32_DataModel());
System.out.println("***** " + l);
System.out.println(ClassLayout.parseClass(A.class, l).toPrintable());
l = new HotSpotLayouter(new X86_64_DataModel());
System.out.println("***** " + l);
System.out.println(ClassLayout.parseClass(A.class, l).toPrintable());
l = new HotSpotLayouter(new X86_64_COOPS_DataModel());
System.out.println("***** " + l);
System.out.println(ClassLayout.parseClass(A.class, l).toPrintable());
}
public static class A {
Object a;
Object b;
}
}
其在不同环境下的内存布局如下:
参考:
原文:https://www.cnblogs.com/neocxf/p/12600114.html