Java对象的组成

122 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情

java对象的组成

对象头+实例化数据+对齐填充

  • 使用openJdk中的工具类JOL来分析java对象布局
// 引入maven
<!-- 使用JOL工具类,打印对象头 -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.8</version>
</dependency>
  • 测试打印对象信息
public static void main(String[] args) {
    L l = new L();
    System.out.println(l);
    String s = ClassLayout.parseInstance(l).toPrintable();
    System.out.println(s);
}
  • 打印结果信息

image.png

java的对象头

  • Java对象的对象头由 mark word 和  klass pointer 两部分组成

    • mark word存储了同步状态、标识、hashcode、GC状态等等
    • klass pointer存储对象的类型指针,该指针指向它的类元数据
    • klass pointer中如果应用的对象过多,使用64位的指针将浪费大量内存。64位的JVM比32位的JVM多耗费50%的内存。我们现在使用的64位 JVM会默认使用选项 +UseCompressedOops 开启指针压缩,将指针压缩至32位
  • 对象头信息

image.png

  • 锁状态标识含义
biased_locklock状态
001无锁
101偏向锁
000轻量级锁
010重量级锁
011GC标记
  • lock:  锁状态标记位,该标记的值不同,整个mark word表示的含义不同
  • biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁
  • age:Java GC标记位对象年龄
  • identity_hashcode:对象标识Hash码,采用延迟加载技术。当对象使用HashCode()计算后,并会将结果写到该对象头中。当对象被锁定时,该值会移动到线程Monitor中
  • thread:持有偏向锁的线程ID和其他信息。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念
  • epoch:偏向时间戳
  • ptr_to_lock_record:指向栈中锁记录的指针
  • ptr_to_heavyweight_monitor:指向线程Monitor的指针
  • 对象头前八位显示
unused:1age:4biased_lock:1lock:2
00000001

实例化数据

基本数据类型所占用大小

类型大小(字节)
int4
byte1
long8
short2
float4
double8
char2
boolean1

对齐填充

64位虚拟机上对象的大小必须是8的倍数

示例中对齐填充大小为7字节,填充完后对象大小为24字节