gc 全称是 Garbage Collection,中文叫垃圾回收,是编程语言里面自动内存管理机制,核心作用就是自动识别程序里面不再被使用的内存对象,并且把这块内存回收释放,交还给系统重新分配使用,主流 Java Csharp Go 等语言都内置 gc,和 C C++ 需要程序员手动 malloc 和 free 管理内存不一样,gc 把内存释放这件事交给虚拟机或者运行时自动处理,减少人工写内存释放代码,避免忘记释放内存造成内存泄漏,也防止提前释放内存引发野指针崩溃,但是 gc 不是完全没有代价,运行的时候会占用 CPU,还会出现短暂停顿,也就是常说的 STW 停顿,很多后端性能调优核心工作,就是针对 gc 参数进行调优,降低停顿时间,提升程序整体吞吐量。设计 gc 的根本原因,程序运行过程中会不断创建对象,内存资源是有限的,如果废弃对象一直占用内存不释放,内存会持续上涨,最终触发内存耗尽,程序直接 OOM 崩溃,早期手动内存管理对开发人员要求很高,容易出现各类内存 bug,所以现代高级语言引入 gc 自动管理,把内存生命周期判断封装在运行时内部,开发人员只需要关注业务代码,不需要手动释放对象,不同语言 gc 实现算法并不相同,没有一套 gc 算法适合所有场景,所以才有分代回收 标记清除 标记复制 标记整理多种方案,用来平衡吞吐量 停顿时间 内存占用三个指标。
gc 核心基础概念
| 术语 | 解释 |
|---|---|
| GC Roots | 根对象,作为判断对象是否存活的起点,比如栈局部变量 静态变量 |
| 存活对象 | 还被 GC Roots 引用,后续程序还会使用,不能回收 |
| 垃圾对象 | 没有任何引用指向,程序再也访问不到,可以回收 |
| STW | Stop The World,gc 执行阶段暂停业务线程 |
| 吞吐量 | 单位时间业务代码运行时间占总时间比例,gc 占用时间越少吞吐量越高 |
主流 gc 算法
第一 标记清除,先遍历标记所有存活对象,之后统一清除没有标记的垃圾对象,优点实现简单,缺点清除之后内存碎片化严重。
第二 标记复制,把内存分成两块,存活对象复制到另一块内存,整块清空原区域,优点没有内存碎片,缺点需要额外一半内存空间。
第三 标记整理,标记存活对象之后,把存活对象向一端移动整理,之后清理边界外垃圾,兼顾无碎片,不需要双倍内存,缺点移动对象开销更大。
第四 分代收集,把对象分成年轻代老年代,新对象放年轻代,熬过多次回收晋升到老年代,大部分对象朝生夕死,年轻代使用复制算法,老年代使用标记整理或者标记清除,Java 虚拟机经典分代 gc 就是这个思路。
常见 gc 分类
- 串行 GC,单线程回收,适合小内存客户端场景,停顿明显
- 并行 GC,多线程并行回收,优先提升吞吐量,服务器常用
- 并发 GC,gc 线程和业务线程大部分时间同时运行,减少 STW 停顿,适合低延迟业务
gc 调优基础步骤
第一步 开启 gc 日志,把每次 gc 发生时间 回收前后内存 停顿时间输出到日志文件。
第二步 分析 gc 日志,确认是年轻代回收频繁,还是老年代回收停顿过长。
第三步 调整堆内存大小,调整年轻代老年代比例,更换 gc 收集器。
第四步 压测验证,观察 gc 频率 停顿时间 吞吐量指标变化,确认调优效果。
第五步 上线持续监控,通过监控指标观察 gc 是否稳定,排查大对象 内存泄漏问题。
gc 常见误区
第一 不是只要有 gc 就不会内存泄漏,gc 只能回收无引用对象,如果对象还被静态集合 监听器持有引用,gc 依然无法回收,依然会内存泄漏。
第二 gc 不是越快越好,频繁 gc 会消耗 CPU,业务吞吐下降,调优目标是平衡,不是让 gc 完全不发生。
第三 不同语言 gc 实现差异很大,Go 的 gc 和 Java 的 gc 算法机制不能直接照搬,不能认为所有 gc 原理完全一致。
gc 作为高级语言自动内存管理核心机制,依靠可达性分析判断对象存活,搭配标记类算法自动回收无用内存,降低手动内存管理的编码负担,同时带来 STW 和 CPU 开销,后端开发需要理解 gc 原理,会看 gc 日志,掌握基础调优手段,处理内存相关性能问题。
【常见问题】
问题 1 gc 里面 STW 是什么意思
回答 1 gc 里面 STW 全称 Stop The World,是 gc 执行的时候暂停业务应用线程,保证内存引用状态稳定,避免回收过程对象引用变动,STW 停顿过长会造成接口卡顿。
问题 2 gc 能不能彻底避免内存泄漏
回答 1 gc 不能彻底避免内存泄漏,gc 只能回收不再被引用的对象,如果对象仍然被长生命周期引用持有,gc 无法回收,依然会出现内存泄漏。
问题 3 gc 分代回收为什么要区分年轻代老年代
回答 1 gc 分代回收是基于对象朝生夕死的特性,大部分新对象很快变成垃圾,年轻代使用复制算法快速回收,长期存活对象晋升老年代,减少全堆扫描,提升 gc 整体效率。
问题 4 手动内存管理和 gc 最大区别是什么
回答 1 gc 是运行时自动识别回收垃圾内存,手动内存管理需要开发人员主动释放内存,gc 减少野指针和忘记释放内存 bug,但是会额外占用 CPU 并且产生停顿。
【免责申明】
本文内容为 gc 垃圾回收机制通用技术科普,不同编程语言虚拟机运行时实现存在差异,具体参数和实现细节请以对应语言官方文档为准,调优方案仅作为学习参考,生产环境调优需要结合业务压测验证。


