「JVM 内存管理」HotSpot VM 对象概要

HotSpot VM 在 Java 堆中的对象分配、布局、访问的全过程;

1. 对象的创建

在语言层面 new 一个对象(数组和 Class 对象例外),对应在 JVM 中是一条字节码 new 指令,JVM 会首先检查这个指令参数是否可以通过常量池定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析、初始化;若否,必须先执行相应加载过程;待类加载检查通过,JVM 则为新生对象分配内存;

分配内存的两种方式

  • 指针碰撞(Bump The Pointer),假设 Java Heap 中内存绝对规整,所有使用过的内存被放到一边,空闲内存放到另一边,中间以一个指针指向分界点;内存分配仅仅是把指针向空闲空间挪动一段与对象大小相等的距离,这种分配方式被称为指针碰撞;简单而高效;Java Heap 的内存并不是规整的,无法简单实用指针碰撞的方式进行内存分配,需要 GC 具备压缩整理(Compact)的能力(Serial、ParNew 等);

  • 空闲列表(Free List),JVM 维护一个记录着所有可用内存块信息的列表,内存分配就是从列表中一块足够大的空间为对象划分同等大小的内存,并更新空闲列表,这种分配内存的方式即空闲列表;基于清理(Sweep)算法(CMS)的 GC 理论上只能通过空闲列表进行内存分配(实际可以通过从空闲列表拿大块空间作为缓冲区的方式进行指针碰撞分配,Linear Allocation Buffer);

解决并发情况下线程安全的两种方式

  • 同步处理,采用 CAS 和失败重试的方式保障更新的原子性;
  • 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB,-XX:+/-UseTLAB 启停),每个线程在 JVM Heap 预先分配一小块内存,哪个线程需要分配内存,就使用哪个 TLAB;分配新的 TLAB 才需要同步锁;

对象内存初始化

内存分配完成后,JVM 将分配到的内存空间都初始化为零值(使用 TLAB 则提前至 TLAB 分配时);这保障对象的实例字段在代码中可以不赋值就拥有其数据类型对应的零值;

对象头设置

根据 JVM 当前运行状态的不同(如是否启用偏向锁等),将一些信息(如:对象的类型指针、对象的 HashCode、对象的 GC 分代年龄等)存放到对象的对象头(Object Header);

对象初始化

字节码 new 指令后一般跟随一个 invokespecial 指令(Java Compiler 会将 new 关键字编译成这两条字节码指令,但也存在其他生成方式不含 invokespecial),用于执行 <init>() 方法(构造函数、静态代码块);

2. 对象的内存布局

对象的内存布局分为三部分:对象头(Object Header)、实例数据(Instance Data)、对齐填充(Padding);

对象头

  • Mark Word,存放对象自身运行时数据,如 HashCode、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向实践戳等;
  • 类型指针,指向对象的类型元数据的指针(并非所有 JVM 实现都会在对象上保留类型指针);

实例数据

存储程序代码中所定义的各类型的字段内容(自身定义的、从父类继承的);存储顺序受 JVM 分配策略参数(-XX:FieldsAllocationStyle)和字段在源码中定义顺序影响,默认分配顺序:longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers,OOPs),等宽字段分配在一起,父类变量在子类变量之前,子类中窄字段可以插入父类变量的空隙(需要开启 +XX:CompactFileds=true,默认是开启的);

对象填充

起占位符的作用(HotSopt VM 自动内存管理要求对象的大小必须是 8 字节的整数倍,对象实例数据部分未对齐时,通过对齐填充补全),非必然存在,无特殊含义;

3. 对象的访问定位

Java 程序通过 Stack 上的 reference 数据操作 Heap 上的具体对象;通过 reference 访问实际对象的方式主要分使用句柄直接指针两种,具体则由 VM 的实现而定;

使用句柄

栈上 reference 指向句柄(存储句柄地址);Java 堆中有一块内存将作为句柄池,专用于存储句柄;而句柄中包含对象实例数据和类型数据的地址信息;

reference 中存储的是稳定句柄地址,对象被移动(GC)时只会改变句柄中的实例数据指针,reference 无效修改;

直接指针

栈上 reference 指向对象(存储对象地址),访问对象本身不需多一次间接访问的开销,速度快(HotSpot 的主流方式);


上一篇:「JVM 内存管理」运行时数据区(Runtime Area)
下一篇:「JVM 内存管理」OutOfMemoryError 异常

PS:感谢每一位志同道合者的阅读,欢迎关注、评论、赞!


参考资料:

  • [1]《深入理解 Java 虚拟机》
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Aurelius-Shu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值