一、对象回收判断依据
1. 可达性分析算法(主流JVM采用)
判定标准:
-
GC Roots作为起点,向下搜索引用链
-
不在任何引用链上的对象判定为可回收
GC Roots包括:
1. 虚拟机栈中引用的对象(局部变量)
2. 方法区中类静态属性引用的对象
3. 方法区中常量引用的对象
4. 本地方法栈中JNI引用的Native对象
5. Java虚拟机内部引用(Class对象、异常对象等)
2. 引用计数法(Python等使用)
实现原理:
class Object {
int refCount = 0; // 引用计数器
void addRef() { refCount++; }
void release() { if(--refCount == 0) delete this; }
}
缺陷:
-
无法解决循环引用问题(如A引用B,B引用A)
二、主流GC算法分类
1. 标记-清除(Mark-Sweep)
执行过程:
-
标记所有可达对象
-
清除未标记对象
特点:
-
产生内存碎片
-
适用于老年代(CMS收集器部分阶段使用)
2. 标记-复制(Mark-Copy)
内存布局:
Eden区(80%) + Survivor0(10%) + Survivor1(10%)
执行过程:
-
将Eden和Survivor0存活对象复制到Survivor1
-
清空Eden和Survivor0
特点:
-
无内存碎片
-
空间利用率仅90%
-
适用于新生代(ParNew等收集器)
3. 标记-整理(Mark-Compact)
执行过程:
-
标记存活对象
-
将存活对象向一端移动
-
清理边界外内存
特点:
-
无内存碎片
-
移动对象开销大
-
适用于老年代(Serial Old等收集器)
4. 分代收集(Generational)
组合策略:
-
新生代:标记-复制
-
老年代:标记-清除/标记-整理
理论依据: -
弱分代假说(绝大多数对象朝生夕死)
-
强分代假说(熬过多次GC的对象难以消亡)
三、现代JVM主流GC算法
1. HotSpot虚拟机默认选择
| JDK版本 | 新生代 | 老年代 |
|---|---|---|
| JDK7/8 | Parallel Scavenge | Parallel Old |
| JDK9+ | G1(全区域统一处理) | |
| JDK17 | ZGC(实验特性) |
2. G1收集器(Garbage-First)
核心创新:
-
将堆划分为多个Region(默认2048个)
-
优先回收价值最大(垃圾最多)的Region
-
可预测的停顿时间模型(-XX:MaxGCPauseMillis)
执行流程:
-
初始标记(STW)
-
并发标记
-
最终标记(STW)
-
筛选回收(Evacuation)
四、深度问题解析
Q1:如何手动触发GC?System.gc()一定有效吗?
关键点:
-
System.gc()只是建议而非强制 -
添加
-XX:+DisableExplicitGC参数会忽略调用 -
更可靠方式:
// 通过内存分配施压 byte[] pressure = new byte[1024*1024*1024]; -
推荐使用JMX触发诊断性GC:
jcmd <pid> GC.run
Q2:如何判断对象是否被回收?
实践方法:
-
finalize()方法(不推荐):
protected void finalize() throws Throwable { System.out.println("对象即将被回收"); } -
引用队列监控:
ReferenceQueue<Object> queue = new ReferenceQueue<>(); WeakReference<Object> ref = new WeakReference<>(new Object(), queue); // 监控queue.poll()获取被回收的引用 -
JVMTI工具:
JNIEXPORT void JNICALL callback_object_free(jvmtiEnv *jvmti, jlong tag) { printf("Object freed: %lld\n", tag); }
Q3:为什么G1取代CMS成为默认收集器?
技术演进原因:
-
内存碎片问题:
-
CMS使用标记-清除,长期运行后触发Full GC
-
G1通过压缩避免碎片(类似标记-整理)
-
-
停顿时间控制:
-
CMS难以预测停顿时间
-
G1可设置最大停顿目标(默认200ms)
-
-
大内存适配:
-
CMS在堆>4GB时性能下降明显
-
G1可有效管理数十GB堆内存
-
-
算法统一:
-
G1不再严格分代,适合现代应用内存特征
-
五、GC算法选择建议
| 场景 | 推荐收集器 | 参数配置示例 |
|---|---|---|
| 小型应用(<4GB) | Parallel Scavenge | -XX:+UseParallelGC |
| 低延迟要求 | G1 | -XX:+UseG1GC -XX:MaxGCPauseMillis=100 |
| 超大堆(>32GB) | ZGC | -XX:+UseZGC -Xmx64g |
| 云原生环境 | Shenandoah | -XX:+UseShenandoahGC |
理解GC算法有助于:
-
合理配置JVM参数
-
优化应用内存使用
-
诊断性能问题
-
展示系统级调优能力
445

被折叠的 条评论
为什么被折叠?



