大家好,我是程序员二叉。
简介
本文一次性讲透对象存活判定、GC Roots、三大GC回收算法、分代回收设计逻辑、对象晋升规则、Minor/Major/Full GC区别、STW、主流垃圾收集器、三色标记法等全套核心考点。欢迎点赞收藏关注。
一、如何判断对象是否存活?引用计数 & 可达性分析
1. 引用计数法
给每个对象分配一个引用计数器,对象被引用时计数器+1,引用失效释放时计数器-1;计数器数值为0代表对象可回收。
实现逻辑简单、判定响应速度快,回收时无停顿压力。
无法解决对象循环引用场景,两个对象互相引用,计数器永远无法归零,造成内存泄漏,因此HotSpot JVM并未采用此方案。
2. 可达性分析算法(Java虚拟机标准方案)
以固定的GC Roots作为起始根节点,向下遍历整个引用链路;遍历过程中能连通到的对象标记为存活,无法抵达的对象判定为垃圾可回收。
完美规避循环引用问题,判定精准稳定;是HotSpot、Android ART虚拟机统一使用的存活判断方式。
二、GC Roots包含哪些对象
作为可达性分析起点、永远不会被回收的根对象,一共5大类:
三、三大垃圾回收算法及各自优缺点
1. 标记-清除(Mark-Sweep)
- 两次全堆扫描,整体回收效率偏低
- 清理后产生大量不连续内存碎片,大对象分配容易OOM
2. 复制算法(Copy)
3. 标记-整理(Mark-Compact)
四、新生代用复制算法,老年代用标记整理的原因
新生代适配复制算法
老年代适配标记-整理算法
五、新生代对象晋升到老年代的四大条件
对象每熬过一次Minor GC,年龄计数器+1;年龄达到-XX:MaxTenuringThreshold默认值15,自动晋升老年代。
Survivor区中,相同年龄所有对象占用内存总和 > Survivor空间一半;大于等于该年龄的全部对象直接晋升,无需等到15岁。
对象大小超过-XX:PretenureSizeThreshold阈值,不走新生代,直接创建在老年代,避免Eden反复复制大数组/大实例。
Minor GC后存活对象总量大于Survivor剩余容量,无法放入Survivor,存活对象直接转移到老年代。
六、Minor GC、Major GC、Full GC定义与触发条件
1. Minor GC
- 回收范围:仅新生代(Eden+两块Survivor)
- 触发条件:Eden内存空间填满
- 特点:执行频繁、停顿时间短、速度快
2. Major GC
- 回收范围:仅老年代区域
- 触发条件:老年代内存占用接近上限
- 特点:速度远慢于Minor GC,常伴随一次Minor GC一起发生
3. Full GC
- 回收范围:整个堆(新生代+老年代)+ 元空间
- 触发条件:
- 手动调用System.gc()
- 老年代空间不足
- Minor GC担保失败
- 元空间Metaspace内存耗尽
- 特点:停顿时间最长、性能损耗最大,线上业务要极力减少Full GC频率
七、什么是STW(Stop The World)
垃圾回收执行标记、复制、整理操作时,所有Java业务用户线程全部暂停冻结,只有GC后台线程允许运行。
保证可达性分析标记阶段,对象之间的引用关系不会被业务线程修改,防止标记错乱、存活对象误回收。
没有任何收集器能彻底消除STW;G1、ZGC、Shenandoah等低延迟收集器的核心目标就是尽可能压缩STW停顿时长。
八、主流常用垃圾收集器分类
新生代收集器
老年代收集器
整堆分代收集器(全堆管理)
九、三色标记法原理
三色标记是CMS、G1、ZGC等并发GC用来做可达性标记的核心算法,用来拆分标记阶段,降低STW时长。





