Java 虚拟机 - 2.3 HotSpot虚拟机对象
对象的创建
Step1 类加载检查
当发现一条new指令时,检查:
- 该指令的参数是否能在常量池中定位到一个类的符号引用;
- 并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
Step2 为新生对象分配内存
对象所需的内存大小在类加载完成之后便可完全确定。分配方式有两种,选择哪种分配方式由java堆是否规整决定;而java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。
两种分配方式:
- 指针碰撞(Bump the Pointer): 内存规整
- 空闲列表 (Free List): 内存不规整
Step3 分配内存如何保证线程安全
两种方案:
- 所有分配内存动作进行同步处理。(不推荐)
- 每个线程在java堆预先分配一小块内存,称为本地线程分配缓存(Thread Local Allocation Buffer, TLAB)。各个线程会先在TLAB里面分配内存,该操作不用同步。只有当TLAB用完并分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。
Step4 初始化为零值
虚拟机将分配到的内存都初始化为零值(不包括对象头)。如果使用TLAB,这一步可以提前到TLAB分配时进行。
保证了对象的实例字段可以不赋初始值就能直接使用。
Step5 对象头必要设置
例如,这个对象是哪个类的实例、如何找到类的元数据,对象的hash code, GC分代年龄,是否启用偏向锁...
Step6 执行init方法
<init>执行之前,所有值都是零值。执行完new指令后,会接着执行<init>,把对象按照程序员的意愿初始化。
对象的内存布局
在HotSpot虚拟机中,对象在内存中存储的布局分为3块区域:对象头(Header),实例数据(Instance Data), 对齐填充(Padding)。
Part1 对象头(Header)
细分为两部分:
- Mark Word, 存储对象自身的运行时数据 :哈希码hashcode, GC分代年龄, 锁状态标志,线程持有的锁。。。这部分数据很多, 虚拟机为其分配的32bit (32位虚拟机) / 64bit (64位虚拟机) 不够用,因为会根据对象的状态复用自己的存储空间。
- 类型指针:即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
- (仅针对java数组):有一块区域保存数组长度
Part2 实例数据(Instance Data)
实例数据,存放对象真正储存的有效信息,也是在程序代码中所定义的各种类型的字段内容。
- 无论是父类的继承来的,还是在子类定义的,都要记录;
- 记录顺序受到:1.虚拟机分配策略参数(FieldsAllocationStyle); 2.字段在java源码中定义的顺序
- 默认的分配策略:long/double, int, short/char, byte/boolean, oops(Ordinary Object Pointers)...相同宽度的字段总是优先分配在一起。
- 在默认的情况下,父类中定义的变量会出现在子类之前;当CompactFields值为true时(默认为true),那么子类中较窄的变量也可能插入到父类变量的空隙之中。
精度(低1-高5) | ||
1 | byte(1字节) | Byte |
short(2字节) | Short | |
char(2字节) | Character | |
2 | int(4字节) | Integer |
3 | long(8字节) | Long |
4 | float(4字节) | Float |
5 | double(8字节) | Double |
NA | boolean(未定) | Boolean |
Part3 对齐填充(Padding)
不是必须存在的,也没有特别的意义,就是占位符。HotSpot VM 的自动管理系统要求对象起始地址/对象的大小必须是8字节的整数倍。
- 对象头部分正好是8字节的倍数(1倍或者2倍)
- 当对象实例数据没有对齐时,就需要通过对齐填充来补全。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?