对象实例化内存布局与访问定位

对象实例化内存布局与访问定位

对象实例化

创建对象的方式

  1. 使用new关键字 (调用无参或者有参构造器创建)
  2. Class的newInstance方法(调用的是无参构造器,而且必须是Public修饰的构造器)
  3. Constructor类的newInstance方法
  4. clone方法,不调用构造器,对象需要实现Cloneable接口,默认为浅复制1
  5. 反序列化
  6. 三方库利用asm字节码技术2,动态生成对象2

创建对象步骤

  1. 判断对象对应的类是否加载 链接 初始化
    当虚拟机需要创建对象的时候,首先判断这个创建对象的指令的参数,能不能在常量池中找到对应的类的符号引用,并检查符号引用所代表的类是不是已经被加载 解析 初始化;如果没有,使用双亲委派模式,以ClassLoader 和报名+类名为key查找对应的class文件;如果找不到对应的class文件,抛出异常;如果找到,就将class文件加载到内存,生成Class类对象。

  2. 分配内存

3.处理并发问题
创建对象是比较频繁的操作,如何保证创建新对象的线程安全性?有两种解决方式

  • CAS
  • TLAB
  1. 初始化内存空间
    内存分配结束之后,申请到的空间的值不是固定的,所以拿到内存空间之后,还需要初始化内存空间,这一步将分配到的空间都初始化为0

  2. 设置对象头
    JVM将对象所属类 对象的hashcode 对象的GC信息 锁信息这些数据 写入对象头

  3. 执行init方法初始化
    这一步才是我们写Java代码感知到的初始化,也就是构造器。这一步开始初始化成员变量,执行实例代码块,调用构造器等等

对象内存分布

Java 对象在内存中通常由三部分组成(按顺序排列):

  • 对象头(Object Header)

  • 实例数据(Instance Data)

  • 对齐填充(Padding)
    在这里插入图片描述

对象头
  1. Mark Word
  • 作用:存储对象自身的运行时数据

  • 大小:32 位 JVM:4 字节;64 位 JVM:8 字节(开启指针压缩时为 4 字节)
    在这里插入图片描述

  • unused:未使用的区域。

  • identity_hashcode:对象最原始的哈希值,就算重写hashcode()也不会改变。

  • age:对象年龄。

  • biased_lock:是否偏向锁。

  • lock:锁标记位。

  • ThreadID:持有锁资源的线程ID。

  • epoch:偏向锁时间戳。

  • ptr_to_lock_record:指向线程栈中lock_record的指针。

  • ptr_to_heavyweight_monitor:指向堆中monitor对象的指针。

  1. Klass Pointer(类型指针)

  2. 数组长度(仅数组对象需要)

实例数据(Instance Data)

存储对象的所有字段值,排列顺序受以下规则影响:

  1. 基本类型优先:按 long/double → int/float → short/char → byte/boolean 的顺序

  2. 引用类型最后:所有引用类型(如 String, Object)放在末尾

  3. 父类字段优先:父类的字段出现在子类之前

  4. 紧凑排列策略:-XX:CompactFields=true(默认)允许子类窄字段插入父类空隙

对齐填充(Padding)
  • 作用:确保对象总大小是 8 字节的倍数

  • 原因:CPU 按块访问内存(通常 64 位系统按 8 字节对齐),对齐可提升访问效率

  • 规则:对象头 + 实例数据 的总大小不是 8 的倍数时自动填充

访问定位

句柄访问(Handle)

栈中的引用
句柄池地址
句柄结构
实例数据指针
类型数据指针
堆中对象实例数据
方法区类元数据

工作流程

  • 栈帧中的引用变量存储句柄池地址

  • 通过句柄池地址找到句柄结构

  • 句柄包含两个指针:

    • 实例数据指针 → 指向堆中对象实例

    • 类型数据指针 → 指向方法区类元数据

  • 通过实例数据指针访问对象字段

优缺点

  • 优点:对象移动安全:GC 移动对象时只需更新句柄中的实例指针,栈中引用不变;引用稳定:适合频繁移动对象的 GC 算法(如标记-整理)

  • 缺点:性能损耗:每次访问需两次指针跳转(额外内存访问);内存占用:句柄池消耗额外内存(通常 4-8 字节/对象)

直接指针访问(Direct Pointer)

栈中的引用
堆中对象地址
对象头
类型指针
方法区类元数据
实例字段数据

工作流程

  • 栈帧中的引用变量直接存储堆内存地址

  • 通过地址直接访问对象头

  • 对象头中的 Klass Pointer 指向方法区类元数据

  • 直接访问对象字段数据

优缺点

  • 优点:访问速度快:减少一次内存寻址(性能提升 20-30%);内存紧凑:无句柄池开销,减少内存碎片

  • 缺点:GC 复杂性:移动对象时需更新所有引用(需遍历栈、寄存器等);依赖优化:需要高效的 GC 算法(如复制算法+卡表)


  1. 引用类型的属性(如对象、数组),浅复制仅复制指向该子对象/数组的内存地址(引用),而不是在内存中创建一个全新的副本;对于基本数据类型,浅复制会直接复制值本身。 ↩︎

  2. 一个强大而底层的 Java 库,用于直接操作 Java 字节码(.class 文件) ↩︎ ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ThetaarSofVenice

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值