java对象生命周期始于堆内存分配、终于垃圾回收;引用变量存于栈中,仅保存指向堆中对象的地址,对象实例(含对象头、实例数据、对齐填充)才真正分配在堆中。

Java对象的生命周期始于堆内存分配,终于垃圾回收;而引用类型本身并不在堆中分配,它只是栈中保存的一个地址值,指向堆里的实际对象。真正分配在堆中的,是对象实例(包括对象头、实例数据和对齐填充),不是引用变量。
对象创建时的堆内存分配流程
执行 new MyClass() 时,JVM 在堆中完成以下关键步骤:
-
类检查与加载:先确认
MyClass已完成加载、链接和初始化; - 内存分配:在堆中划分一块连续空间(通过指针碰撞或空闲列表),大小由类结构在编译期确定;
-
零值初始化:将分配区域除对象头外全部置为默认值(
int→0、Object→null等); - 设置对象头:写入 Mark Word(含哈希码、GC年龄、锁状态)和 Klass Pointer(指向类元数据);
-
调用构造方法:执行
<init></init>方法,完成字段显式赋值、代码块、构造器逻辑; -
返回引用:把堆中对象起始地址赋给栈中的引用变量(如
MyClass obj)。
引用变量的存储位置与本质
引用变量(如 obj)本身不存于堆中,而是存储在栈帧里(局部变量)或方法区/堆中(静态字段、成员变量)。它的作用是保存一个内存地址,这个地址指向堆中某个对象的起始位置。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 多个引用可指向同一堆对象,修改对象状态会相互可见;
- 引用类型(
String、List等)的变量,其值就是这个地址,不是对象本身; - 基本类型变量(
int、boolean)直接存值,不涉及堆引用。
不同引用类型对对象生命周期的影响
是否被回收,取决于对象是否可达——即是否存在一条从 GC Roots 出发、经由强引用链能到达该对象的路径。引用类型决定了这条链的“强度”:
-
强引用(最常见):如
MyClass obj = new MyClass();,只要 obj 存在且未置 null,对象不会被回收; - 软引用:内存不足时才回收,适合缓存场景;
-
弱引用:下次 GC 就可能回收,常用于避免内存泄漏(如
WeakHashMap); - 虚引用:仅用于跟踪对象被回收的时机,必须配合引用队列使用。
TLAB 与堆分配优化细节
为减少多线程竞争,JVM 默认启用 TLAB(Thread Local Allocation Buffer):
- 每个线程拥有独立的小块堆内存,对象优先在 TLAB 中分配;
- TLAB 耗尽时,再在共享堆中分配(可能触发同步机制如 CAS);
- 大对象或 TLAB 不适配时,直接在 Eden 区分配;
- 对象分配失败且无法扩容时,可能触发 Minor GC。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










