JVM垃圾回收与调优核心面试笔记(引用计数/GC算法/CMS/G1/参数调优)

JVM垃圾回收与调优核心面试笔记(引用计数/GC算法/CMS/G1/参数调优)

文章标签:#jvm #gc #面试 #java #后端

前言

本文为JVM垃圾回收核心复习笔记,覆盖对象存活判定、三大GC算法、CMS执行流程、G1分区机制、JVM参数调优全链路考点,适配面试突击与实战复盘,逻辑对标HashMap笔记风格,便于快速记忆与背诵。


一、对象存活判定算法:引用计数 & 可达性分析

GC第一步:判断对象是否"死亡",主流两种算法,HotSpot仅用后者。

1.1 引用计数法(Reference Counting)

  • 原理:为每个对象维护引用计数器,有引用+1,引用失效-1,计数器=0则可回收。
  • 优点:实现简单、判断高效、可立即回收。
  • 致命缺陷 :无法解决循环引用,导致内存泄漏。
java 复制代码
// 循环引用示例(引用计数无法回收)
public class CircularRef {
    Object instance;
    public static void main(String[] args) {
        CircularRef a = new CircularRef();
        CircularRef b = new CircularRef();
        a.instance = b;
        b.instance = a;
        a = null; b = null; // 无外部引用,但计数均为1
    }
}
  • 结论:HotSpot未采用,仅作历史了解。

1.2 可达性分析算法(主流)

  • 核心思想 :以GC Roots 为起点,递归遍历引用链,不可达对象=垃圾。
  • GC Roots固定范围(必背) :
    1. 虚拟机栈局部变量表引用的对象
    2. 方法区静态属性引用的对象
    3. 方法区常量引用的对象
    4. 本地方法栈JNI引用的对象
    5. 活跃线程对象
  • 流程:STW暂停→从GC Roots遍历→标记可达对象→回收不可达对象。
  • 优势:解决循环引用、精准判定、适配JVM运行模型。

二、三大基础GC算法:复制 / 标记清除 / 标记整理

2.1 复制算法(Copying)

  • 核心 :内存分等大两块,每次只用一块,满时将存活对象复制到另一块,清空原块。
  • 优点:无碎片、复制高效、适合存活对象少的场景。
  • 缺点:内存利用率仅50%,存活对象多则效率暴跌。
  • 适用 :新生代(Eden+Survivor,8:1:1),Minor GC默认用此算法。

2.2 标记-清除算法(Mark-Sweep)

  • 流程:先标记所有存活对象→统一清除未标记垃圾。
  • 优点:无需移动对象、实现简单。
  • 缺点 :内存碎片严重、效率随垃圾数量波动。
  • 适用:老年代早期方案,CMS底层算法。

2.3 标记-整理算法(Mark-Compact)

  • 流程 :标记存活→将存活对象向一端压缩→清除端外内存。
  • 优点:无碎片、内存规整。
  • 缺点:需移动对象、全程STW、效率偏低。
  • 适用:老年代(Parallel Old、Serial Old)。

三大算法对比表

算法 效率 内存碎片 移动对象 适用代
复制 高 无 是 新生代
标记-清除 中 严重 否 老年代(CMS)
标记-整理 低 无 是 老年代

三、CMS 执行流程与优缺点

CMS(Concurrent Mark Sweep):低延迟老年代收集器 ,以最短STW为目标,面试高频。

3.1 核心流程(4阶段,2次STW)

  1. 初始标记(Initial Mark)STW
    仅标记GC Roots直接关联对象,速度极快。
  2. 并发标记(Concurrent Mark)并发
    与业务线程并行,遍历全引用链标记存活对象,耗时最长但无停顿。
  3. 重新标记(Remark)STW
    修正并发标记期间引用变动导致的漏标,停顿短于Full GC。
  4. 并发清除(Concurrent Sweep)并发
    异步回收垃圾,不移动对象,业务线程可继续运行。

3.2 优点

  • 大部分阶段并发,停顿极低,适配响应敏感型服务。
  • 不移动对象,降低STW开销。

3.3 缺点(必背)

  1. CPU敏感:并发阶段抢占算力,核心数<4时吞吐量暴跌。
  2. 浮动垃圾:并发清除时新产生垃圾无法当次回收,需预留内存。
  3. 内存碎片:基于标记-清除,碎片多易触发Full GC。
  4. 并发失败:内存不足退化为Serial Old,停顿剧增。

四、G1 核心思想与分区机制

G1(Garbage-First):服务端大堆首选 ,平衡停顿可控+高回收效率,JDK9+默认收集器。

4.1 核心思想

  • 化整为零 :堆拆分为独立Region,按需回收,不扫描全堆。
  • 垃圾优先 :优先回收垃圾最多、收益最大的Region,故名G1。
  • 停顿可预测 :通过-XX:MaxGCPauseMillis指定目标,动态调整回收量。

4.2 分区机制(Region)

  • 堆划分 :约2048个等大Region,大小1MB~32MB(2的幂)。
  • 动态角色 :每个Region可充当Eden/Survivor/Old/Humongous(巨型对象),逻辑分代、物理不连续。
  • Humongous Region:存储>1.5个Region的大对象,避免大对象分配失败。
  • Remembered Set:记录跨Region引用,避免全局扫描,加速回收。

4.3 G1回收模式

  1. Young GC:回收新生代Region,复制算法,STW可控。
  2. Mixed GC :回收新生代+高收益老年代Region,不回收全老年代。
  3. Full GC :并发失败触发,单线程收集,需避免。

五、JVM 常用参数调优(生产实战版)

按内存、GC、监控、最佳实践分类,直接复制可用。

5.1 堆内存核心参数

复制代码
-Xms8g -Xmx8g        # 初始堆=最大堆,禁止扩容震荡
-Xmn3g               # 新生代大小,推荐堆1/3~1/2
-XX:SurvivorRatio=8  # Eden:S0:S1=8:1:1
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m  # 元空间
-Xss1m               # 线程栈,默认1MB

5.2 GC收集器参数

复制代码
-XX:+UseG1GC                  # 生产首选G1
-XX:MaxGCPauseMillis=200      # G1停顿目标ms
-XX:+UseConcMarkSweepGC       # CMS启用(老项目)
-XX:+CMSScavengeBeforeRemark  # CMS重新标记前先Young GC,缩短STW
-XX:ParallelGCThreads=8       # GC线程数≈CPU核心数

5.3 监控与故障定位

复制代码
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump/  # OOM自动dump
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  # GC日志
-Xlog:gc*:file=gc.log  # JDK9+日志
-XX:+DisableExplicitGC  # 禁用System.gc()

5.4 调优最佳实践

  1. Xms=Xmx,避免堆动态扩容。
  2. 新生代不宜过小,防止频繁Minor GC与过早晋升。
  3. G1优先于CMS,大堆(>8G)必用G1。
  4. 开启OOM dump,定位泄漏必备。
  5. 禁用System.gc(),避免突发Full GC。

总结(面试速背版)

  1. 对象存活:引用计数(循环引用BUG) 、可达性分析(HotSpot标准)。
  2. GC算法:复制(新生代)、标记清除(CMS)、标记整理(老年代)。
  3. CMS:4阶段2次STW,低延迟但有碎片、浮动垃圾、CPU敏感。
  4. G1:Region分区、垃圾优先、停顿可控,生产首选。
  5. 调优:固定堆、合理新生代、选对收集器、开启监控。

需要我把本文整理成一页A4面试背诵清单(纯要点+口诀)吗?

相关推荐
天河归来10 小时前
第三方接口不稳定,如何让核心任务继续完成
java·大数据
Knight_AL11 小时前
Java 文件下载时文件名中的 `#` 被转换成 `%23`?一次 URL 编码与解码问题排查
java·开发语言
利威尔xu11 小时前
Go IM 源码实战(14):本地缓存快 3000 倍,失效却难 10 倍
后端·缓存·微服务·面试·golang
砚底藏山河12 小时前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
利威尔xu12 小时前
Go IM 源码实战(13):30 个会话只有 2 个红点,未读数错在三条路径
redis·后端·微服务·面试·golang
猿究院_夏燊13 小时前
MySQL 的四种隔离级别
java·数据库·mysql
码流子13 小时前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
霸道流氓气质14 小时前
AI 流式对话与实时聊天平台:SSE 解码竞态、有状态会话隔离与背压取消的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
云创智城-yuncitys14 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
文丑颜不良啊14 小时前
LeetCode1661~1680题目解析
java·leetcode