如果搜索过“java基础”或者“java面试题”,你几乎一定会碰到GC(垃圾回收)这个话题。它既是很多人口中的八股文,也是线上系统出故障时最让人头疼的环节。我印象很深的是,运维同事半夜发来消息,说HBase集群GC延迟太高,写入请求大面积超时。打开监控一看,老年代使用率曲线像锯齿一样来回跳动,每次Full GC都让业务毛刺持续好几秒。那一刻我才意识到,过去对GC的认知全停留在“自动回收内存”这一句话上,等到真正要定位问题、调整参数时,脑子里全是零散的知识点,根本连不成线。
这篇文章就是按我自己重新梳理GC体系的思路写的。从对象怎么判定为垃圾,到各类收集器的设计取舍,再到日志怎么看、参数怎么调,我把这几个月踩过坑、查过源码、复盘过的内容一次性整理出来。适合正在准备Java面试的开发者,也适合已经在生产环境里被GC问题折磨的同行。全文尽量说人话,但该严谨的地方不会含糊。
1. 先回答“是什么”:GC的职责与一次OOM事故的启示
1.1 一次真实OOM:日志里没有答案,只有“insufficient memory”
先从一个典型事故说起。某个内部服务的错误日志里连续出现 java.lang.OutOfMemoryError: Java heap space,更早一些时候只有一行简短提示:java: outofmemoryerror: insufficient memory。第一次遇到这种情况,本能反应是“堆不够,加内存”,于是把 -Xmx 从4GB加到8GB。结果服务撑了三个星期,又倒下了,日志还是同样的报错。
问题到底在哪?后来通过分析堆转储才发现,服务里有一个全局缓存,键是用户ID,值是一个大对象,用户量一增长,缓存本身就把堆占满了。堆再大也经不起无边界增长。这个案例说明GC不是简单的“内存不够就触发垃圾回收”,它解决的是“如何判断哪些对象可以安全回收、何时回收、用什么方式回收”的问题。如果我们连内存区域都搞不清楚,遇到OOM只能瞎猜。
1.2 内存区域地图:GC主要活动在哪个区域
要理解GC,第一步是分清JVM运行时数据区。JVM把内存分为程序计数器、虚拟机栈、本地方法栈、方法区(Java 8之后是元空间)、Java堆这几块。程序计数器、虚拟机栈、本地方法栈的生命周期都跟随线程,栈帧执行完弹栈就释放,不需要GC介入。真正需要GC重点照顾的是堆,其次是方法区里的类型卸载和常量池回收。
| 区域 | 是否有OOM可能 | GC是否参与 | 说明 |
|---|---|---|---|
| 程序计数器 | 否 | 否 | 当前线程执行字节码的行号指示器 |
| 虚拟机栈 | 是(StackOverflowError或OOM) | 否 | 栈帧随方法调用结束自动释放 |
| 本地方法栈 | 是 | 否 | 为native方法服务 |
| Java堆 | 是 | 是 | GC最核心的区域,对象分配都在这里 |
| 方法区/元空间 | 是 | 是 | 类元数据、常量池回收,JDK8后用本地内存实现 |
有一个容易搞混的点:字符串常量池在JDK 7之后被移到了堆里,所以 String.intern() 相关的问题可能触发堆OOM。而类元数据在JDK 8以后使用本地内存,默认情况下只受到操作系统内存限制,如果加载的类太多,会出现 OutOfMemoryError: Metaspace。虽然这也属于OOM,但和堆OOM的原因完全不同,排查方向也完全不一样。
1.3 堆内外的边界:为什么元空间溢出也要算GC问题
很多人觉得GC只管堆,其实不然。方法区在JDK 8之后虽然换成了元空间,但它的回收依然属于GC的一部分。JVM只有在类加载器可以卸载、该类所有实例都回收、该类的Class对象没有任何地方引用时,才可能卸载类。Tomcat这类容器频繁热部署时,如果类加载器没有释放,元空间就会被撑爆。解决方法往往是检查是否有静态变量引用了被替换的类加载器,而不是单纯调大 -XX:MaxMetaspaceSize。
理解了内存区域,再回头看OOM,就能建立第一个排查框架:如果是堆OOM,先想对象分配速率和存活对象数量;如果是元空间OOM,先想类加载器是否泄漏;如果是创建线程时OOM,先想栈空间和线程数量。GC调优不是一上来就改参数,而是先定位到底哪个区域出了问题。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 判断“谁是垃圾”:可达性分析与其他边界情况
2.1 引用计数为什么被主流JVM放弃
判断对象能否回收,最直观的方案是引用计数。每个对象维护一个计数器,每有一个地方引用它,计数加一;引用失效,计数减一;计数为零时回收。这个思路简单高效,但有一个致命缺陷:处理不了循环引用。A对象持有B的引用,B对象持有A的引用,两者在外部都没有入口,但计数一直不为零,就永远无法回收。
Python的垃圾回收机制
