java对象结构

对象布局

HotSpot虚拟机 markOop.cpp 中的 C++ 代码注释片段,描述了 64bits 下 mark-word 的存储状态,也就是如上图结构示意。

markOop.cpp 源码地址: jdk8/hotspot/file/vm/oops/markOop.hpp

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)实例数据(Instance Data)对齐填充(Padding)

  • mark-word:对象标记字段占4个字节,用于存储一些列的标记位,比如:哈希值、轻量级锁的标记位,偏向锁标记位、分代年龄等。
  • Klass Pointer:Class对象的类型指针,Jdk1.8默认开启指针压缩后为4字节,关闭指针压缩(-XX:-UseCompressedOops)后,长度为8字节。其指向的位置是对象对应的Class对象(其对应的元数据对象)的内存地址。
  • 对象实际数据:包括对象的所有成员变量,大小由各个成员变量决定,比如:byte占1个字节8比特位、int占4个字节32比特位。
  • 对齐:最后这段空间补全并非必须,仅仅为了起到占位符的作用。由于HotSpot虚拟机的内存管理系统要求对象起始地址必须是8字节的整数倍,所以对象头正好是8字节的倍数。因此当对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

另外,在mark-word锁类型标记中,无锁,偏向锁,轻量锁,重量锁,以及GC标记,5种类中没法用2比特标记(2比特最终有4种组合00011011),所以无锁、偏向锁,前又占了一位偏向锁标记。最终:001为无锁、101为偏向锁。

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class A {
int i = 3;
int i1 = 3;
}

class B {
public static void main(String[] args) {
A a = new A();
// Object o = new Object();
// System.out.println(o + " 十六进制哈希:" + Integer.toHexString(o.hashCode()));
// System.out.println(ClassLayout.parseInstance(a).toPrintable());
System.out.println(ClassLayout.parseInstance(a).toPrintable());
}
}
1
2
3
4
5
6
7
8
9
10
11
com.yzw.juc.markWord.A@5cad8086 十六进制哈希:5cad8086
com.yzw.juc.markWord.A object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 86 80 ad (00000001 10000110 10000000 10101101) (-1384086015)
4 4 (object header) 5c 00 00 00 (01011100 00000000 00000000 00000000) (92)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 int A.i 3
16 4 int A.i1 3
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
  • 运行结果

验证

  • 如上图: markWord 占8字节 Klass Point占4字节 实际的对象数据占8字节 最后四个字节用于填充对齐

  • 如上图: 对象的头部也存放了hash,只不过这个哈希值是倒过来的

    关于倒过来的问题是大小端存储导致的

    • Big-Endian:高位字节存放于内存的低地址端,低位字节存放于内存的高地址端
    • Little-Endian:低位字节存放于内存的低地址端,高位字节存放于内存的高地址端

markWord结构

markWord