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

相关推荐
XiYang-DING1 小时前
【Spring】 SpringBoot 配置文件
java·spring boot·spring
唯情于酒1 小时前
IdentityServer4学习笔记
笔记·学习
那小子、真烦1 小时前
Hermes Agent Chat 方法分析
java·开发语言
jameslogo1 小时前
JVM入门
jvm
快乐得小萝卜1 小时前
笔记:TREX工具-4
笔记
01_ice1 小时前
Java抽象类和接口
java·开发语言
小马爱打代码2 小时前
Spring源码 第七篇:Spring Boot 自动配置原理深度拆解
java·spring boot·spring
日取其半万世不竭2 小时前
给 Docker 容器设置 CPU 和内存限制,避免单个服务拖垮整机
java·docker·容器
铁皮哥2 小时前
【agent 开发】Claude Code 的 Skill 是怎么被加载的?从 name/description 到 SKILL.md 再到资源文件
java·服务器·数据库·python·gitee·github·软件工程