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面试背诵清单(纯要点+口诀)吗?

相关推荐
程序员天天困3 分钟前
Arthas ognl 表达式从入门到实战:掌握在线调试最强的表达式引擎
java·jvm·后端
IT_Octopus39 分钟前
Spring Boot 中 ThreadLocal 请求上下文的完整生命周期
java·spring boot·spring
thesky1234561 小时前
智能体面试准备(九):工作流编排——DAG 与状态机两种范式的取舍与手写实现
面试·agent·状态机·工作流·智能体
2501_926978331 小时前
认知边缘的双向耦合:从核技术类比到智力货币时代
人工智能·经验分享·笔记·ai写作
用户40966601317511 小时前
Lombok 你用对了吗?@Data 之外的 6 个隐藏神器
java·后端·代码规范
hanlin031 小时前
刷题笔记:力扣第242、349题(哈希表)
笔记·算法·leetcode
Revolution611 小时前
reactive 对象重新赋值后,表单为什么没有恢复默认值
前端·vue.js·面试
梅头脑1 小时前
交易跨10个库、日均千万订单——选错一次分布式事务方案,加班三个月重写
java·分布式
HeiSenBerg1 小时前
Android Handler 机制完全解析:从源码到内存泄漏,一篇就够了
面试
久久学姐1 小时前
基础转码学 AI:Java+Python 双语言入门,3 个月可落地实战项目
java·python·ai·转码·实战项目