当前位置: 首页 > news >正文

JVM 垃圾回收(GC)笔记

一、为什么需要垃圾回收(GC)

  • Java 程序运行过程中会不断创建对象,堆内存有限。
  • 无法被引用的对象占用空间,如果不释放,会导致 内存泄漏或内存溢出(OOM)
  • 手动管理内存易出错,Java 引入自动垃圾回收机制。

二、JVM 中的内存区域(重点)

区域说明
程序计数器每个线程私有,记录字节码执行位置
虚拟机栈每个线程私有,保存局部变量表
本地方法栈调用 native 方法时使用
堆(Heap)所有线程共享,垃圾收集的主要区域,保存对象实例
方法区(元空间)保存类信息、常量、静态变量等

三、如何判断对象是否可以被回收?

引用计数法(Reference Counting)

  • 每个对象维护一个引用计数器;
  • 计数为 0 → 可回收;
  • 缺陷:无法处理循环引用。

可达性分析法(Reachability Analysis)(Java 使用)

  • GC Root 出发向外遍历:

    • 方法区静态变量
    • 方法栈局部变量
    • JNI 引用
  • 如果一个对象无法从 GC Root 访问到,则被判定为不可达 → 可回收对象


四、对象的生命周期与回收区域

区域描述
新生代(Young Generation)包括 Eden + 两个 Survivor 区域(S0、S1)
老年代(Old Generation)存放长时间存活的对象
元空间(Metaspace)Java 8 后替代永久代,存类元数据

五、常见垃圾回收算法

复制算法(Copying)

  • 应用于新生代

  • 将 Eden 中的存活对象复制到 Survivor 区;

  • 一般为 Eden + From(S0)+ To(S1):

    • 每次使用其中两个,另一个为空;
  • 优点:没有碎片,效率高;

  • 缺点:内存浪费严重(只用了一半)。


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

  • 应用于老年代

  • 第一步:标记可达对象;

  • 第二步:清除未被标记对象;

  • 缺点

    • 产生内存碎片;
    • 清除速度慢。

标记-压缩(整理)算法(Mark-Compact)

  • 是标记清除的改进;
  • 标记完后把存活对象压缩到一端,释放内存;
  • 避免内存碎片问题,适用于老年代。

分代收集(Generational GC)

  • 新生代使用复制算法老年代使用标记清除或压缩算法

  • 理由:

    • 大多数对象“朝生夕死”,适合复制算法;
    • 老年代对象存活率高,复制开销大,适合标记压缩。

六、常见垃圾收集器

收集器名称作用区域特点
Serial新生代单线程,Stop-The-World,适合单核/小应用
ParNew新生代Serial 的多线程版本
Parallel Scavenge新生代吞吐量优先,适合后台批处理系统
CMS(已废弃)老年代并发收集、低停顿,但容易产生碎片
Serial Old老年代Serial 的老年代版本
Parallel Old老年代Parallel 的老年代版本
G1(推荐)新+老面向服务端,低延迟、可预测停顿
ZGC / Shenandoah新+老超低延迟,适合超大内存(100GB+)应用

七、GC 类型与触发时机

GC 类型触发时机回收区域使用算法
Minor GC新生代满新生代复制算法
Major GC老年代满老年代标记-压缩
Full GC整体内存压力高、元空间满、System.gc()新生代 + 老年代 + 元空间综合算法

八、如何选择垃圾收集器?

单核、资源紧张、客户端程序:

  • 使用 Serial + Serial Old

多核、后台任务型应用、对吞吐量要求高:

  • 使用 Parallel Scavenge + Parallel Old

用户体验要求高、低延迟应用:

  • 使用 G1(JDK9 后默认)、ZGCShenandoah

九、G1 收集器简要说明(面试重点)

  • 将堆划分为多个 Region;
  • 并发执行 Mark 阶段,减少 STW;
  • 优先回收垃圾最多的 Region(Garbage First);
  • 可通过 -XX:MaxGCPauseMillis 控制最大停顿时间;
  • 对大内存友好,JDK9+ 推荐默认使用。

十、调试与配置常用参数

# 查看 GC 日志(JDK8)
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log# 设置新生代大小
-Xmn256m# 设置堆最大/最小值
-Xms512m -Xmx512m# 使用 G1 收集器
-XX:+UseG1GC# 控制最大 GC 停顿时间
-XX:MaxGCPauseMillis=200

十一、垃圾回收相关工具

工具名称说明
jstat查看 JVM 各种运行指标(GC、类加载、堆等)
jvisualvm图形化 JVM 监控工具
jconsole图形化管理工具,可连远程
GCViewer分析 GC 日志
MAT(Memory Analyzer Tool)堆内存分析工具,找内存泄漏

十二、面试高频问题总结

Q1:对象从新生代晋升到老年代的条件?

  • 经历 -XX:MaxTenuringThreshold 次 GC;
  • Survivor 区放不下时,直接进入老年代;
  • Survivor 区年龄分布达到阈值,提前晋升。

Q2:Minor GC 和 Full GC 有什么区别?

  • Minor GC 只回收新生代,频率高,速度快;
  • Full GC 回收整个堆(新生代 + 老年代 + 元空间),频率低,STW 时间长,影响性能。

Q3:如何判断是否发生内存泄漏?

  • GC 后对象仍然没有被释放;
  • 使用 jmap + MAT 工具分析对象引用链。

总结

JVM 垃圾回收的核心是“分代 + 区域 + 策略”,通过合适的算法(复制、标记清除、压缩)和收集器(如 G1、ZGC)实现不同场景下的高效内存管理,是高性能 Java 应用的保障。

十三、三色标记法(Tri-Color Marking)


三色标记法是什么?

三色标记法 是现代垃圾回收器中用于并发标记阶段的一种对象可达性追踪算法。其核心目的是在应用线程运行过程中,仍能安全、准确地标记存活对象,避免漏标或误回收。

它被广泛应用于:

  • CMS
  • G1
  • ZGC
  • Shenandoah 等收集器的并发 GC 实现中

三种颜色含义

颜色状态说明
白色初始状态,表示对象未被访问;最终仍为白的对象将被回收
灰色对象已被访问,但其引用的其他对象尚未全部扫描完毕
黑色对象已访问完毕,自身和引用对象都已处理,判定为存活

在这里插入图片描述

标记流程

  1. 所有对象初始为白色;

  2. GC Root 集合作为入口,加入灰色集合;

  3. 循环处理灰色对象:

    • 标记为黑;
    • 扫描其引用的白色对象 → 转为灰色;
  4. 灰色集合为空后:

    • 剩余未访问的白色对象即为不可达对象 → 回收。

并发 GC 中的“漏标”问题

在并发标记时,用户线程仍在运行,可能会导致以下情况:

  • 对象 A 被标记为黑;
  • A 指向对象 B(白色);
  • 此时用户线程将 A → B 的引用断开,并把 C(灰)指向 B;
  • 后续 GC 先处理了 A(黑),再处理 C(灰)时不再追踪 B;
  • B 由于“断开”后未再被扫描,最终仍为白色 → 被错误回收(漏标)!

解决办法

现代 GC 通常通过以下机制解决漏标问题:

技术描述说明
增量更新(Incremental Update)当黑对象新增引用白对象时,重新将白对象置为灰色,等待重新扫描
SATB(Snapshot At The Beginning)保留标记开始时的对象引用快照,即使中途引用断了,也按初始快照追踪对象存活性

应用收集器

GC 收集器是否使用三色标记法附加机制
CMS增量更新
G1增量更新
ZGCSATB
ShenandoahSATB

三色标记法通过黑 / 灰 / 白三种状态动态追踪对象引用,确保在并发标记时依然准确地识别出所有存活对象,是现代低停顿 GC 的基础核心算法。

http://www.dtcms.com/a/263296.html

相关文章:

  • Nestjs框架: Nestjs 复杂企业应用场景架构设计分析
  • WPF中依赖属性和附加属性
  • API接口安全-2:签名、时间戳与Token如何联手抵御攻击
  • 时序数据集---UWave
  • 显著性预测 SUM
  • tcpdump工具交叉编译
  • 《JMS事务性会话彻底解析:消息监听中的 commit、rollback 和幂等设计》
  • 每天一个前端小知识 Day 17 - 微前端架构实战与 Module Federation
  • 记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。
  • BI软件选型:7款可私有部署产品对比
  • 利用不坑盒子的Copilot,快速排值班表
  • 在 Vue3 + Element Plus 中实现 el-table 拖拽排序功能
  • 【c语言课程设计】单选题考试系统(无链表,含码源)
  • 多校区在线跑腿小程序源码系统搭建平台 PHP+MySQL组合开发 含完整的搭建教程
  • 商品中心—16.库存分桶调配的技术文档
  • 【分布式】自定义统一状态机流转设计
  • Flowable01SpringBoot项目的引入--------------------每天都会更新,自学中
  • 组成原理精讲课--硬布线控制器和微程序控制器
  • STM32之火焰传感器模块(四针)
  • 11、类加载器
  • 项目:数据库应用系统开发:智能电商管理系统
  • 【Springai】项目实战进度和规划
  • 【FR801xH】富芮坤FR801xH之PMU GPIO
  • OpenCV CUDA模块设备层----- 正切(tangent)运算函数tan()
  • Python 数据分析与机器学习入门 (五):Matplotlib 数据可视化基础
  • R1-Searcher使用强化学习增强语言模型解决问题的搜索能力
  • WebSocket 的核心原理和工作流程
  • 前端Vue面试八股常考题(一)
  • 企业流程知识:《超越再造:以流程为中心的组织如何改变我们的工作和生活》读书笔记
  • 力扣面试150(7/150)