JVM的内存管理,本质上是一套在有限资源下平衡吞吐量、响应延迟与内存占用的精妙策略。这套策略的核心逻辑基于一个务实原则:按对象的生命周期划分区域管理,根据回收性价比选择算法,再依据堆内存实时压力决定回收时机。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
内存被划分为几个逻辑区域
JVM堆内存被划分为新生代(Young Gen)和老年代(Old Gen)等逻辑区域。在JDK 8及以后,方法区被元空间(Metaspace)取代,元空间不再占用堆内存,而是使用本地内存,这直接解决了永久代(PermGen)常导致的内存溢出(OOM)问题。
- 新生代内部细分为一个Eden区和两个Survivor区(S0和S1)。新创建的对象绝大多数优先在Eden区分配。
- 对象经历多次小型垃圾回收(Minor GC)后若仍存活,会被“晋升”到老年代。触发晋升的条件包括年龄阈值、大对象直接分配以及Survivor区空间不足等。
- 元空间存放类的元数据,其大小由实际加载的类数量决定,不再受限于JVM堆内存大小,是一项实用改进。
GC触发不是定时而是基于压力驱动
许多人误以为GC按固定时间表执行,实际上GC触发完全是被动事件,属于典型的压力驱动型。
- Eden区满时,新对象无法分配,触发Minor GC(又称Young GC),目标是清理新生代,将存活对象复制到Survivor区或直接晋升到老年代。
- 老年代空间不足,或Minor GC后晋升对象放不下,会触发更重量级的Major GC或Full GC。手动调用
System.gc()仅是一个“建议”,JVM有权忽略。
- 现代垃圾回收器如G1、ZGC的逻辑更复杂,会实时监控预测停顿时间、垃圾对象占比、并发标记进度等指标,动态调整回收节奏与力度,力求在性能与响应间找到最优解。
不同代采用不同回收算法
分代设计的精华在于利用“大多数对象朝生暮死”的经验规律,为不同区域定制回收算法。
- 新生代对象存活率低,适用复制算法,只需复制少量存活对象,效率高且不产生内存碎片,就像打扫一个只有少数人留下的房间,请他们到隔壁后清空原房间。
- 老年代对象存活率高且体积大,复制算法成本过高,常用标记-整理算法或标记-清除算法。前者如整理书架消除碎片,后者只标记清除但可能留下内存空洞,需后续压缩策略弥补。
- ZGC和Shenandoah等前沿回收器通过读屏障和并发转移技术,实现几乎不受堆大小影响的亚毫秒级停顿,将并发垃圾回收推向极致。
对象能否被回收取决于可达性分析
判断对象是否“存活”,JVM采用可达性分析算法,而非简单引用计数(会循环引用问题)。
- 算法起点是GC Roots,包括:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、常量池中引用的对象以及本地方法栈中JNI引用的对象。
- 从这些根节点出发遍历,所有能被直接或间接引用到的对象视为“存活”,未被任何路径引用的对象标记为“可回收”。
- 值得注意的是,
finalize()方法在JDK 9之后已标记为弃用,不应用作资源清理的兜底手段。当前推荐使用try-with-resources语句或Cleaner类进行可靠资源管理。