堆中对象分配、布局和访问的全过程
原创大约 2 分钟
堆中对象分配、布局和访问的全过程
本文将深入探讨HotSpot虚拟机中Java堆中对象分配、布局和访问的全过程。
对象的创建
在Java中,创建对象通常使用new
关键字,而在JVM中,创建对象的过程如下:
1、类加载检查
JVM首先检查new
指令所引用的类是否已加载、连接和初始化。 如果没有,会先执行类加载过程。
2、分配内存
JVM为新对象分配内存,其大小在类加载完成时确认,内存分配的方式:
- 指针碰撞: 适用于规整的堆内存,将内存分为已使用和未使用两部分,通过移动指针分配内存。
- 空闲列表: 适用于不规整的堆内存,JVM维护一个空闲列表,从中找到合适的内存块进行分配。
使用压缩整理功能的收集器(如Serial、ParNew)通常采用指针碰撞分配,而基于标记-清除(Sweep)算法的CMS收集器使用空闲列表分配。
线程安全的内存分配方式:
- 同步处理: 通过同步操作或CAS加重试机制确保原子性。
- 线程本地分配缓冲(TLAB): 每个线程在Java堆中预先分配一小块内存,分配时在
TLAB
中进行, 只有TLAB
耗尽分配新的TLAB
时才才需同步。- 通过
-XX:+UseTLAB
参数来启用TLAB
。
- 通过
3、初始化零值(不包括对象头)
JVM将分配的内存空间(不包括对象头)初始化为零值,确保对象字段在未显式初始化时可直接使用。
4、设置对象头
JVM设置对象头,包括:
- Mark Word: 存储对象的哈希码(调用
Object::hashCode()
时计算)、GC分代年龄、锁信息等。 - 类元数据指针: 指向对象所属类的元数据,确定对象是哪个类的实例。
5、执行<init>
方法
至此,在JVM层面,一个新的对象已经产生了。 但从Java程序视角,对象创建才刚刚开始,所有的字段都还为零值。 只有构造方法<init>
执行后,对象才按照程序员的意图完成初始化,成为一个真正可用的对象。