# JVM内存规范下篇
作者:Ethan.Yang
博客:https://blog.ethanyang.cn (opens new window)
相关源码参考: https://github.com/YangYingmeng/_014JVM (opens new window)
# 一、运行时数据区图解
JVM 的内存整体分为两大区域:
- 非堆区(Non-Heap):方法区、代码缓存、本地方法栈、线程栈等;
- 堆区(Heap):用于存放对象实例,是垃圾回收器的主要工作区域。
堆内部分为:
- 年轻代(Young Generation):用于存放新创建的对象;
- 老年代(Old Generation):用于存放生命周期较长或经历多次回收仍存活的对象。
年轻代又细分为:
- Eden 区
- 两个 Survivor 区(S0 / S1)
Eden、S0、S1 的比例通常为 8 : 1 : 1。

说明:
- 每个线程独享虚拟机栈和程序计数器。
- 堆和方法区为所有线程共享。
- 对象创建、指向关系、以及生命周期的变化都发生在堆中。
# 二、对象创建内存分配过程
当在 Java 中通过
new关键字创建对象时:类加载检查
若类尚未加载,会先进行加载、验证、准备、初始化等步骤。
分配内存空间
JVM 会根据对象大小在堆上分配空间,默认优先在 Eden 区。
初始化对象头
JVM 会在对象头写入:
- Mark Word(哈希码、GC 年龄、锁状态等)
- Klass Pointer(指向类元数据的指针)
执行构造方法
按照字段定义顺序初始化成员变量,然后执行
<init>构造函数。返回引用
最终返回引用地址,存储在栈帧的局部变量表中。
# 三、对象的生命周期
# 创建阶段
JVM 为对象分配内存空间,并从超类到子类依次完成
- 静态成员初始化
- 成员变量按顺序初始化
- 调用构造方法(先递归调用父类构造方法,再调用子类构造方法)
对象构造完成后,被变量持有,即进入应用阶段。
# 应用阶段
对象至少被一个强引用持有,程序可以正常访问并操作该对象。
# 不可见阶段
超出作用域或引用被修改,但仍存在潜在引用路径。
# 不可达阶段
对象无法被任何强引用访问,可进入 GC 待回收队列。
# 终结阶段
如重写了 finalize(),GC 会先调用一次;若执行后仍不可达,则进入回收阶段。
# 内存释放
GC 回收对象占用空间,等待新的内存分配。
⚠️ 建议避免使用
finalize():它会导致 GC 多一次标记过程,并可能引发对象“复活”问题。
# 四、线程与对象的内存交互
- 每个线程拥有独立的虚拟机栈(局部变量表、操作数栈等);
- 所有线程共享堆和方法区;
- 当方法中定义对象时,局部变量表中存储的是“堆中对象的引用”;
- 多线程访问共享对象时,通过堆中的实例完成交互,而不是栈之间直接通信。
← JVM内存规范上篇 垃圾回收机制前置知识 →