1. java对象创建流程(大白话版)
咱们java对象被创建的过程大致如下,即:
在 JVM 中对象的创建,从⼀个 new 指令开始:
- 首先检查这个指令的参数是否能在常量池中定位到⼀个类的符号引用
- 检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,就先执行相应的类加载过程
- 类加载检查通过后,接下来虚拟机将为新生对象分配内存。
- 内存分配完成之后,虚拟机将分配到的内存空间(但不包括对象头)都初始化为零值。
- 接下来设置对象头,请求头⾥包含了对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。
没听懂?没关系,咱们来看看下面这个例子:
想象你在秋招时一路过关斩将,现在终于准备入职了,这时候会有以下流程:
- 背景调查 → 检查类是否已加载(HR查你的学历)
- 分配工位 → 分配内存(给你分一个工位)
- 初始化设备 → 内存清零(工位电脑装好系统)
- 贴工牌 → 设置对象头(给你发工牌和权限)
- 入职培训 → 执行构造函数(教你公司规则)
这个入职的流程就跟咱们java对象创建的过程差不多,下面咱们来分步骤一一详解。
2. 分步骤详解
Step 1:类加载检查
new指令触发时,JVM会问:"这个类合法吗?"
这时候会检查常量池中的符号引用,触发类加载机制(加载 → 验证 → 准备 → 解析 → 初始化)
Step 2:分配内存
- 方式1:指针碰撞(内存规整时)
- 方式2:空闲列表(内存碎片化时)
通过CAS + 失败重试保证线程安全,可能使用TLAB(线程私有分配缓冲区)
就好像工位分配有两种策略:连续工区直接划一块(指针碰撞),或从碎片工位里拼凑(空闲列表)。

Step 3:内存清零
将分配的内存初始化为零值(int→0,boolean→false,引用→null),保证对象实例字段不赋初值也能直接使用。就好比给你的工位电脑格式化,装好干净的系统。
Step 4:设置对象头
对象头内容:
- Mark Word:哈希码、GC分代年龄、锁状态等
- 类型指针:指向类元数据的指针
对象头占12字节(64位JVM开启压缩指针时),就好像给你工牌贴上姓名、工号、部门等信息。
Step 5:执行构造函数
执行<init>方法(显式初始化成员变量),从子类到父类递归调用构造函数
HR带你熟悉公司,布置你的工位(这才是你看到的new Object()的最终效果)。
步骤 | 技术细节 | 比喻 |
类加载检查 | 双亲委派机制,元数据验证 | 入职前的背景调查 |
分配内存 | CAS + TLAB避免并发冲突 | 抢会议室避免冲突 |
内存清零 | 零值初始化(JVM层) | 工位电脑格式化 |
对象头设置 | Mark Word + 类型指针 | 工牌信息(姓名/部门) |
构造函数执行 | 程序员可见的初始化(Java层) | 布置工位(放私人物品) |
3. 代码示例
Object obj = new Object();
JVM背后做的事:
1. 检查Object类是否加载 → 没加载则加载类
2. 分配内存(假设8字节)
3. 内存清零 → 所有字段为0/null
4. 设置对象头(MarkWord + 类型指针指向Object.class)
5. 调用Object的构造函数(这里是个空方法)
4. 高频面试问题
(1)为什么先清零再执行构造函数?
答:保证对象创建时字段一定有初始值(避免脏数据)。
(2)内存分配如何保证线程安全?
答: CAS + 失败重试 或 TLAB(线程本地分配缓冲)。
(3)对象头和对象体是什么关系?
答:对象头是元数据(如锁、GC信息),对象体是实例数据。