专栏 编程工程

1.2.1 Java 性能与调优 · JVM 内存模型与 GC 算法全对比

JVM 内存模型 + 7 大 GC 收集器对比 + 选型决策。

1. 选题理由

Java 后端面试 90% 必问 GC,线上 OOM/Full GC 故障 100% 离不开内存模型。一句话定位:这篇把 JVM 运行时数据区、对象存活判定、4 类算法思想、7 款收集器横向对比、参数调优模板压在一篇里,翻这一篇就够。

2. JVM 内存模型

按《Java 虚拟机规范》(JSR-337 第 2 版) 划分,线程私有区随线程生死,线程共享区由 GC 接管。

区域 归属 异常 关键参数
PC 寄存器 / 虚拟机栈 / 本地方法栈 线程私有 StackOverflowError -Xss 默认 512K~1M
堆 Heap 线程共享 OutOfMemoryError -Xms -Xmx
元空间 Metaspace 线程共享(本地内存) OutOfMemoryError -XX:MaxMetaspaceSize
直接内存 DirectMemory NIO 堆外 OOM,但较小堆可见 -XX:MaxDirectMemorySize
// 验证堆外内存存在 — 分配 1G 但不释放
ByteBuffer.allocateDirect(1024 * 1024 * 1024);
// 堆可能只占 200M,实际 RSS 已达 1.2G+

调研依据:JEP 387(JDK 16) 把 ZGC 的 metaspace 纳入并发管理;JDK 8 用 PermGen,JDK 8+ 改为 Metaspace 走本地内存,默认无上限是历史 OOM 重灾区。

3. 对象判定与四大引用

判定算法:从 GC Roots(栈帧局部变量、静态引用、JNI 句柄、活跃线程)出发,可达性分析(Reachability Analysis),不可达即回收候选。finalize() 只救一次且不保证执行,JDK 9 起标记 `@Deprecated。

引用类型 回收时机 典型场景
Strong 强 GC Roots 不可达 普通 new Object()
Soft 软 内存不足前(OOM 前) 图片缓存
Weak 弱 下一次 GC 必回收 WeakHashMap key、ThreadLocal
Phantom 虚 回收后入队,无法 get 堆外内存回收跟踪
WeakReference<byte[]> wr = new WeakReference<>(new byte[1024]);
System.gc();
// wr.get() 大概率为 null

4. GC 算法四大思想

算法 原理 优点 缺点
标记-清除 Mark-Sweep 两遍扫描 简单,不留空 碎片、两次遍历
复制 Copying Eden + 2 Survivor 8:1:1 无碎片,快 浪费 Survivor 区
标记-整理 Mark-Compact 末段滑动对象 无碎片,空间连续 移动成本高
分代 Generational 弱分代假说:对象朝生夕死 综合最优 实现复杂

调研依据:HotSpot 年轻代用复制,老年代用标记-整理;CMS 是唯一商用标记-清除,ZGC/Shenandoah 改用染色指针+读屏障实现”并发整理”。

5. 七大收集器横向对比

收集器 代 算法 STW 范围 目标延迟 JDK 适用堆
Serial 新 复制 全 STW - 1.3+ <100M 客户端
ParNew 新 复制 全 STW - 1.4+ CMS 搭档
Parallel Scavenge 新 复制,关注吞吐 全 STW - 1.4+ 后台批处理
Serial Old 老 标记-整理 全 STW - 1.3+ 客户端兜底
Parallel Old 老 标记-整理 全 STW - 1.6+ 吞吐优先
CMS 老 标记-清除(并发) 初始/重新标记 <1s 1.5~14 中等堆
G1 全 Region + 增量整理 混合阶段 百毫秒级 1.7+ → 9 默认 4G~几十G
ZGC 全 染色指针+读屏障 <1ms 亚毫秒 11+ TB 级
Shenandoah 全 转发指针+读屏障 <10ms 毫秒级 12+ TB 级

调研依据:JDK 9 起 G1 为默认,JDK 15 起 ZGC 可生产(JEP 377),JDK 14 CMS 被 deprecated,JDK 21 虚拟线程要求 G1/ZGC 协奏。

6. 选型决策树 + 实战参数

决策顺序:堆 < 4G 用 Parallel(吞吐优先);4~32G 用 G1(平衡);32G+ 追求低延迟用 ZGC;Red Hat 生态偏好 Shenandoah。

# G1 通用生产模板(JDK 11/17 适用)
-Xms8g -Xmx8g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:G1HeapRegionSize=16m
-XX:+ParallelRefProcEnabled
# 容器环境关键 — 让 JVM 感知 cgroup 限制
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=75.0
# 可观测
-Xlog:gc*,safepoint:file=gc.log:time,uptime,level,tags:filecount=5,filesize=50m

观测命令:jstat -gcutil <pid> 1s 看各区占比,jcmd <pid> GC.heap_info 看 Region 分布,Async-Profiler 抓 STW 分布。

调研依据:Alibaba Dragonwell 8/11 默认推荐 G1;字节跳动 K8s 容器场景推荐 -XX:MaxRAMPercentage 取代 -Xmx,避免超卖。

说明 · 本站内容均为学习笔记与经验总结,所有菜谱与技法请结合实际食材、季节与个人口味灵活调整。涉及生食、营养与健康的内容仅供参考,特殊体质或疾病请咨询专业营养师/医生。