编辑
2024-08-04
后端
00
请注意,本文编写于 279 天前,最后修改于 279 天前,其中某些信息可能已经过时。

目录

1. 对象头的组成部分
2. 不同情况下的对象头大小
2.1 32 位 JVM
2.2 64 位 JVM(未启用压缩指针)
2.3 64 位 JVM(启用压缩指针)
3. Mark Word 的内容分配
3.1 无锁状态
3.2 偏向锁状态
3.3 轻量级锁状态
3.4 重量级锁状态
4. 示例分析
总结

在 Java 虚拟机(JVM)中,对象头(Object Header)的大小取决于多个因素,包括 JVM 的位数(32 位或 64 位)、是否启用了压缩指针(Compressed Oops)、以及对象的状态(如锁状态)等。以下是详细的分析:

1. 对象头的组成部分

对象头主要由两部分组成:

  • Mark Word:用于存储对象的运行时数据,如哈希码、分代年龄、锁状态标志等。
  • Klass Pointer:指向对象的类元数据的指针。

2. 不同情况下的对象头大小

2.1 32 位 JVM

在 32 位 JVM 中,对象头的典型大小为 8 字节:

  • Mark Word:4 字节
  • Klass Pointer:4 字节

2.2 64 位 JVM(未启用压缩指针)

在 64 位 JVM 中,如果未启用压缩指针,对象头的典型大小为 16 字节:

  • Mark Word:8 字节
  • Klass Pointer:8 字节

2.3 64 位 JVM(启用压缩指针)

在 64 位 JVM 中,如果启用了压缩指针(Compressed Oops),对象头的典型大小为 12 字节:

  • Mark Word:8 字节
  • Klass Pointer:4 字节

3. Mark Word 的内容分配

Mark Word 的内容会根据对象的状态(如无锁、偏向锁、轻量级锁、重量级锁)而变化。以下是 Mark Word 在不同状态下的典型分配:

3.1 无锁状态

  • 哈希码(HashCode):25 位
  • 分代年龄(Age):4 位
  • 偏向锁标志位(Biased Locking Flag):1 位
  • 锁状态标志位(Lock Flag):2 位

3.2 偏向锁状态

  • 线程 ID(Thread ID):54 位
  • Epoch:2 位
  • 分代年龄(Age):4 位
  • 偏向锁标志位(Biased Locking Flag):1 位
  • 锁状态标志位(Lock Flag):1 位

3.3 轻量级锁状态

  • 指向栈中锁记录的指针:62 位
  • 锁状态标志位(Lock Flag):2 位

3.4 重量级锁状态

  • 指向重量级锁的指针:62 位
  • 锁状态标志位(Lock Flag):2 位

4. 示例分析

假设有一个简单的 Java 类:

java
class MyClass { int a; long b; Object c; }

在 64 位 JVM 中,如果启用了压缩指针,该对象的内存布局可能如下:

  • 对象头(12 字节)
    • Mark Word(8 字节)
    • Klass Pointer(4 字节)
  • 实例数据(24 字节)
    • int a(4 字节)
    • long b(8 字节)
    • Object c(4 字节)
    • 对齐填充(8 字节)

总大小为 36 字节,但由于需要 8 字节对齐,最终对象的大小可能是 40 字节。

总结

对象头的大小在不同情况下会有所不同,主要取决于 JVM 的位数、是否启用压缩指针以及对象的状态。在 32 位 JVM 中,对象头通常为 8 字节;在 64 位 JVM 中,如果未启用压缩指针,对象头为 16 字节;如果启用了压缩指针,对象头为 12 字节。Mark Word 的内容会根据对象的状态而变化,用于存储哈希码、分代年龄、锁状态标志等信息。

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!