news 2026/4/24 9:01:12

【023】GC 入门:分代、常见收集器名词、如何读 GC 日志

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【023】GC 入门:分代、常见收集器名词、如何读 GC 日志

写 Java 代码时,你可能写过这样的代码:

while(true){List<byte[]>list=newArrayList<>();for(inti=0;i<1000;i++){list.add(newbyte[1024*1024]);// 1MB}Thread.sleep(1000);}

运行一段时间后,程序可能会卡顿,甚至OOM。这背后就是垃圾回收(GC)在起作用。

理解 GC,能帮你:

  • 排查线上 OOM 问题
  • 优化程序性能,减少 GC 停顿
  • 合理配置 JVM 参数
  • 选型合适的垃圾收集器

下面我按「分代模型 → GC 算法 → 垃圾收集器 → GC 日志」的顺序往下聊。


1. 为什么需要 GC?🧹

1.1 内存泄漏与 OOM

Java 程序运行时会不断创建对象,这些对象存在堆内存中。如果对象不再使用但没有被回收,堆内存会逐渐耗尽,最终导致OutOfMemoryError

// 内存泄漏示例List<byte[]>list=newArrayList<>();while(true){list.add(newbyte[1024*1024]);// 不断添加,不清理Thread.sleep(1000);}

1.2 GC 的作用

GC(Garbage Collection)自动回收不再使用的对象,释放内存空间。

// GC 自动回收List<byte[]>list=newArrayList<>();for(inti=0;i<1000;i++){list.add(newbyte[1024*1024]);}// 循环结束后,list 超出作用域,变成垃圾// GC 会自动回收这些 byte[] 对象

2. JVM 分代模型 🧬

2.1 堆内存分代

JVM 堆内存分为新生代老年代

堆内存(Heap): │ ├─ 新生代(Young Generation) │ ├─ Eden 区:新对象分配 │ ├─ Survivor 区 S0(From) │ └─ Survivor 区 S1(To) │ └─ 老年代(Old Generation) └─ 长期存活的对象

2.2 新生代

新生代存放新创建的对象,大多数对象生命周期很短。

  • Eden 区:新对象分配区
  • Survivor 区(S0、S1):存放经历一次 Minor GC 后仍然存活的对象
// 大多数对象在新生代分配Useruser=newUser();// 在 Eden 区

2.3 老年代

老年代存放长期存活的对象

  • 经历多次 Minor GC 后仍然存活的对象
  • 大对象(直接分配)
// 大对象直接进入老年代byte[]large=newbyte[10*1024*1024];// 10MB

2.4 元空间(方法区)

元空间(Java 8+)存放类信息、常量、静态变量

Java 7 及之前:永久代(PermGen) Java 8 及之后:元空间(Metaspace)

3. GC 类型与触发条件 🔄

3.1 Minor GC(Young GC)

Minor GC发生在新生代,清理 Eden 区和 Survivor 区。

触发条件:Eden 区空间不足

特点

  • 频率高
  • 停顿时间短
  • 采用复制算法

3.2 Major GC / Full GC

Major GC发生在老年代,清理老年代。

Full GC清理整个堆(新生代 + 老年代)。

触发条件

  • 老年代空间不足
  • 调用System.gc()
  • 元空间不足
  • Minor GC 后晋升对象大小 > Survivor 区

特点

  • 频率低
  • 停顿时间长
  • 影响系统性能

3.3 GC 日志示例

[GC (Allocation Failure) [PSYoungGen: 512K->64K(1536K)] 1024K->512K(2048K), 0.0012345 secs]

4. GC 算法 📊

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

步骤

  1. 标记所有需要回收的对象
  2. 清除标记的对象

缺点

  • 产生内存碎片
  • 效率不高
标记-清除: 标记前:□ ■ □ ■ ■ □ 标记后:□ ■ ■ ■ ■ □ (■ 是垃圾) 清除后:□ □ □ □ □ (碎片)

4.2 复制算法(Copying)

将内存分为两块,每次只使用一块,回收时将存活对象复制到另一块。

优点:无碎片
缺点:内存利用率低

复制算法: ┌─────────┬─────────┐ │ 使用中 │ 空闲 │ └─────────┴─────────┘ 回收时:把存活对象复制到空闲区

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

步骤

  1. 标记需要回收的对象
  2. 整理存活对象,向一端移动
  3. 清除边界外的对象

优点:无碎片
缺点:效率低

标记-整理: 标记前:□ ■ □ ■ ■ □ 整理后:□ □ □ □ □ ■ (存活对象移动到一端) 清除后:□ □ □ □ □

5. 垃圾收集器 🚀

5.1 收集器分类

收集器作用区域算法特点
Serial新生代复制单线程,停顿长
ParNew新生代复制多线程版本
Parallel Scavenge新生代复制吞吐量优先
Serial Old老年代标记-整理单线程
Parallel Old老年代标记-整理多线程
CMS老年代标记-清除并发收集,低停顿
G1全堆标记-整理分区域,可预测停顿
ZGC全堆标记-整理并发,极低停顿

5.2 Serial 收集器

最古老的收集器,单线程执行。

# 启用 Serial 收集器-XX:+UseSerialGC

特点

  • 单线程
  • 简单高效
  • 停顿时间长

适用场景:客户端模式、内存较小的应用

5.3 Parallel 收集器

吞吐量优先的收集器,多线程并行收集。

# 启用 Parallel 收集器-XX:+UseParallelGC# 设置线程数-XX:ParallelGCThreads=4

特点

  • 多线程
  • 吞吐量高
  • 适合后台应用

适用场景:批处理、科学计算

5.4 CMS 收集器

并发收集器,低停顿

# 启用 CMS 收集器-XX:+UseConcMarkSweepGC

工作阶段

  1. 初始标记(STW):标记 GC Roots
  2. 并发标记:并发追踪存活对象
  3. 重新标记(STW):修正标记
  4. 并发清除:清除垃圾

特点

  • 并发收集
  • 停顿短
  • 产生内存碎片

适用场景:互联网应用

5.5 G1 收集器

面向服务端的收集器,可预测停顿

# 启用 G1 收集器-XX:+UseG1GC# 设置停顿目标-XX:MaxGCPauseMillis=200

特点

  • 分区域(Region)
  • 可预测停顿
  • 整理碎片
  • 并发收集

适用场景:大内存应用

5.6 ZGC 收集器

超低停顿的收集器。

# 启用 ZGC-XX:+UseZGC

特点

  • 并发收集
  • 停顿 < 10ms
  • 支持 TB 级内存

适用场景:大内存、低停顿应用

5.7 收集器组合

# 组合 1:Serial + Serial Old-XX:+UseSerialGC# 组合 2:ParNew + CMS-XX:+UseParNewGC-XX:+UseConcMarkSweepGC# 组合 3:Parallel + Parallel Old-XX:+UseParallelGC# 组合 4:G1(独立使用)-XX:+UseG1GC

6. GC 日志解读 📝

6.1 开启 GC 日志

# 打印 GC 日志-XX:+PrintGCDetails-XX:+PrintGCDateStamps-Xloggc:gc.log# 示例java-XX:+PrintGCDetails-Xloggc:gc.logMyApp

6.2 Minor GC 日志

[GC (Allocation Failure) [PSYoungGen: 512K->64K(1536K)] // 新生代:回收前->回收后(总大小) 1024K->512K(2048K), // 堆:回收前->回收后(总大小) 0.0012345 secs] // 停顿时间

6.3 Full GC 日志

[Full GC (Allocation Failure) [PSYoungGen: 512K->0K(1536K)] [ParOldGen: 1024K->1023K(2048K)] 1536K->1023K(3584K), 0.0123456 secs]

6.4 CMS 日志

[GC [1 CMS-initial-mark: 1024K(2048K)] 1024K(2048K), 0.0012345 secs] [GC [CMS-concurrent-mark-start] [GC [CMS-concurrent-mark: 0.0123456/0.0123456 secs] [GC [CMS-concurrent-sweep-start] [GC [CMS-concurrent-sweep: 0.0234567/0.0234567 secs] [GC [CMS-concurrent-reset-start] [GC [CMS-concurrent-reset: 0.0001234/0.0001234 secs]

6.5 G1 日志

[GC pause (G1 Evacuation Pause) young 512M->128M(2048M), 0.0123456 secs] [GC concurrent-root-region-scan-start] [GC concurrent-root-region-scan-end, 0.0012345 secs] [GC concurrent-mark-start] [GC concurrent-mark-end, 0.0234567 secs]

7. GC 调优实战 🎯

7.1 常见 GC 问题

问题现象原因
Minor GC 频繁频繁 minor gc对象分配太快
Full GC 频繁频繁 full gc内存不足、大对象
GC 停顿长页面卡顿堆太大、GC 选型不当
OOM程序崩溃内存泄漏、堆太小

7.2 调优思路

# 1. 调整堆大小-Xms2g-Xmx2g# 2. 调整新生代比例-Xmn512m# 新生代 512MB-XX:NewRatio=2# 新生代:老年代 = 1:2# 3. 调整 Survivor 比例-XX:SurvivorRatio=8# Eden:Survivor = 8:1# 4. 选择收集器-XX:+UseG1GC-XX:MaxGCPauseMillis=200

7.3 监控工具

# jstat:查看 GC 统计jstat-gcutil<pid>1000# jmap:查看堆内存jmap-heap<pid># jcmd:综合诊断jcmd<pid>GC.heap_info

小结

  • GC自动回收不再使用的对象,释放内存
  • 分代模型:新生代(Eden + Survivor)、老年代、元空间
  • GC 算法:标记-清除、复制、标记-整理
  • 垃圾收集器:Serial、Parallel、CMS、G1、ZGC
  • CMS:并发收集,低停顿,适合互联网应用
  • G1:分区域收集,可预测停顿,适合大内存应用
  • GC 日志可以反映 GC 频率、停顿时间、内存使用情况

下一篇(024)预告:JVM 参数入门:堆、栈、元空间与典型模板——常用 JVM 参数、GC 调优参数、性能优化模板。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 9:00:31

思源黑体TTF构建工具:打造完美屏幕显示的中文字体终极方案

思源黑体TTF构建工具&#xff1a;打造完美屏幕显示的中文字体终极方案 【免费下载链接】source-han-sans-ttf A (hinted!) version of Source Han Sans 项目地址: https://gitcode.com/gh_mirrors/so/source-han-sans-ttf 你是否曾经在网页设计或应用开发中遇到过中文字…

作者头像 李华
网站建设 2026/4/24 9:00:05

Real Anime Z部署案例:动漫衍生品设计公司用于盲盒手办3D建模参考图生成

Real Anime Z部署案例&#xff1a;动漫衍生品设计公司用于盲盒手办3D建模参考图生成 1. 项目背景与价值 在动漫衍生品设计领域&#xff0c;盲盒手办的3D建模工作一直面临参考图获取困难的问题。传统方式需要设计师手工绘制多角度概念图&#xff0c;耗时耗力且风格难以统一。R…

作者头像 李华
网站建设 2026/4/24 8:59:22

眼神也能“摸”金,用华为阅读独家首发AI动态漫画看《鬼吹灯》!

作为一名深耕数码领域的博主&#xff0c;看到刚刚发布的华为Pura X Max上独家首发了AI动态漫画&#xff0c;这项功能带来的“眼动撕漫”视觉冲击力&#xff0c;结结实实地让我起了一层鸡皮疙瘩&#xff01;比如以前看《鬼吹灯》这种灵异探险题材&#xff0c;虽然画风写实&#…

作者头像 李华
网站建设 2026/4/24 8:56:12

如何用 JavaScript 实现 Kubernetes 资源伸缩:自动扩缩容实战

如何用 JavaScript 实现 Kubernetes 资源伸缩&#xff1a;自动扩缩容实战 【免费下载链接】javascript JavaScript client 项目地址: https://gitcode.com/gh_mirrors/javascri/javascript Kubernetes 作为容器编排平台的佼佼者&#xff0c;其资源伸缩能力是保障应用稳定…

作者头像 李华