跳至主要內容

堆中对象分配、布局和访问的全过程

会敲代码的程序猿原创JVMJVM大约 2 分钟

堆中对象分配、布局和访问的全过程

本文将深入探讨HotSpot虚拟机中Java堆中对象分配、布局和访问的全过程。

对象的创建

在Java中,创建对象通常使用new关键字,而在JVM中,创建对象的过程如下:

1、类加载检查

JVM首先检查new指令所引用的类是否已加载、连接和初始化。 如果没有,会先执行类加载过程

2、分配内存

JVM为新对象分配内存,其大小在类加载完成时确认,内存分配的方式:

  1. 指针碰撞: 适用于规整的堆内存,将内存分为已使用和未使用两部分,通过移动指针分配内存。
  2. 空闲列表: 适用于不规整的堆内存,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>执行后,对象才按照程序员的意图完成初始化,成为一个真正可用的对象。

对象的内存布局

对象的访问定位