当前位置: 首页 > 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.lryc.cn/news/578161.html

相关文章:

  • LLaMA-Factory框架之参数详解
  • Webpack原理剖析与实现
  • 1.1_2 计算机网络的组成和功能
  • FastDFS分布式储存
  • 华为云Flexus+DeepSeek征文 | ​​接入华为云ModelArts Studio大模型 —— AI智能法务解决方案革新法律实践​
  • 38.docker启动python解释器,pycharm通过SSH服务直连
  • ERP系统Bug记录
  • 前端Vue面试八股常考题(一)
  • 中证500股指期货一手多少钱呢?风险如何?
  • HTML5 实现的圣诞主题网站源码,使用了 HTML5 和 CSS3 技术,界面美观、节日氛围浓厚。
  • 华为云 Flexus+DeepSeek 征文|基于 Dify 平台开发智能客服 AI Agent 的完整实战指南
  • 【STM32HAL-第1讲 基础篇-单片机简介】
  • 前端开发面试题总结-原生小程序部分
  • 《从量子奇境到前端优化:解锁卡西米尔效应的隐藏力量》
  • 《用奥卡姆剃刀原理,为前端开发“减负增效”》
  • 【软考高项论文】论信息系统项目的整体管理
  • 【Java面试】10GB,1GB内存,如何排序?
  • PHP WebSocket服务器搭建指南
  • 从入门到精通:npm、npx、nvm 包管理工具详解及常用命令
  • Springboot + vue + uni-app小程序web端全套家具商场
  • 【Spring】——事务、整合、注解
  • 设计模式-观察者模式(发布订阅模式)
  • UE5 - 制作《塞尔达传说》中林克的技能 - 17 - 遥控炸弹(二)
  • 键盘第一下无反应
  • 基于Spring Boot的绿园社区团购系统的设计与实现
  • 磁悬浮轴承位移信号的高精度估计:卡尔曼滤波算法深度解析
  • MySQL复杂SQL性能优化实战:多表联查与子查询的高效方法
  • 【数据清洗与预处理】-文本采集与处理
  • LoRA 问答微调与部署全流程:基于 LLaMA-Factory + DeepSeek + FastAPI 打造专属大模型
  • Hive SQL 实战:电商销售数据分析全流程案例