写这篇的起因是复习的时候看到这三个概念脑子一片浆糊参考的复习资料写的也不清楚很模糊。后来花时间整理了一遍发现其实没那么复杂写出来给跟我一样曾经懵逼的同学。先别急搞清楚 JVM 堆里有啥要理解这三种 GC首先得知道 JVM 堆内存是怎么分的。不用记太细看个大概就行┌──────────────── 堆Heap ─────────────────┐ │ │ │ ┌─────────────────┐ ┌───────────────┐ │ │ │ 年轻代 │ │ 老年代 │ │ │ │ (Young Gen) │ │ (Old Gen) │ │ │ │ │ │ │ │ │ │ ┌─────┐ ┌────┐ │ │ 存放老油条 │ │ │ │ │Eden │ │Surv│ │ │ 久经考验还没 │ │ │ │ │ │ │ivor│ │ │ 死掉的对象 │ │ │ │ └─────┘ └────┘ │ │ │ │ │ └─────────────────┘ └───────────────┘ │ └──────────────────────────────────────────────┘年轻代又分成 Eden伊甸园和两个 Survivor幸存者区。新创建的对象基本都在 Eden 区。老年代存放那些活了很久的对象从年轻代熬过来的。永久代/方法区java8之后就不在堆中了移动到本地内存的元空间中存储类信息、静态变量、常量、编译后的代码记住这个就够了下面我们一个一个说。Minor GC又称 Young GC —— 年轻代的日常清扫它管哪里只管年轻代Eden Survivor跟老年代没关系。什么时候触发Eden 区满了没地方放新对象了就会触发一次 Minor GC。它怎么干活打个比方Eden 就像一个会议室人对象进进出出。会议室满了保安GC进来清场——活着的人挪到隔壁 Survivor 区没用的直接赶走回收。每活过一轮年龄 1到了一定年龄默认 15就有资格去老年代混了。Eden 满了 → 存活对象复制到 Survivor → 年龄够了 → 晋升老年代特点发生频率很高你的程序一直在创建对象所以 Minor GC 是常客速度快因为年轻代里大部分对象都是短命鬼存活的少回收很快STWStop-The-World时间短通常毫秒级用户基本无感知Major GC —— 老年代的大扫除它管哪里只管老年代。什么时候触发老年代空间不够用了。通常是年轻代的对象一个个晋升过来老年代装不下了。它怎么干活老年代里的对象都是老油条了存活率高所以不能像年轻代那样简单复制。通常用的是标记-清除或者标记-整理算法标记-清除先标记哪些还活着把死的清掉但会产生内存碎片标记-整理标记之后把活的对象往一端挪剩下的空间就是连续的特点频率比 Minor GC 低很多毕竟老年代不是那么容易满速度比 Minor GC 慢因为活着的对象多处理起来费劲STW 时间更长这里就要注意了说实话Major GC 这个概念在不同语境下含义不太一样。有的资料里它特指只回收老年代有的时候它跟 Full GC 混着用。面试的时候如果被问到你最好反问一句您说的是只回收老年代还是整堆回收——这反而显得你懂行。Full GC —— 真正的搬家公司它管哪里整个堆年轻代 老年代Metaspace方法区全部清扫一遍一个都不放过。什么时候触发触发条件比较多常见的几种老年代空间不足Metaspace方法区空间不足代码里调了System.gc()建议 JVM 做一次 Full GCJVM 可以拒绝但一般不会Minor GC 后要晋升到老年代但老年代放不下CMS 收集器并发阶段搞砸了Concurrent Mode Failure特点频率最低但每次搞都是大事耗时最长因为要把整个堆翻一遍STW 时间最长这个才是性能杀手重点来了你做 JVM 调优最重要的目标之一就是减少 Full GC 的频率缩短 Full GC 的时间。因为一次 Full GC 卡个几百毫秒甚至几秒用户端就可能感觉到卡顿了。一张表帮你记住Minor GCMajor GCFull GC回收哪年轻代老年代整个堆 Metaspace啥时候触发Eden 满了老年代满了多种情况多久一次很频繁不太频繁很少希望如此快不快快较慢最慢STW 多长短较长最长进阶老年代不足时到底触发的是 Major GC 还是 Full GC这里有个很多人搞不清楚的点包括很多博客也写得含糊。先说一个常见的理解老年代不足 → 先触发 Major GC → 搞不定内存不足且无法扩展 → 再触发 Full GC听起来很有道理对不对但实际情况没这么简单。Major GC 和 Full GC 并不总是这种先后触发的关系。真正的答案是取决于你用的是哪个垃圾收集器。不同的收集器面对老年代不足这件事处理方式完全不一样。下面分三种情况来说情况一Parallel / Serial 收集器用这类收集器时老年代空间不足直接触发 Full GC。没有先 Major GC 一轮、不行再 Full GC 的过程。上来就是 Full GC年轻代老年代一起清。日志里看到的是这样的[Full GC (Allocation Failure) [PSYoungGen: 2048K-0K(28672K)] [ParOldGen: 65536K-63000K(69632K)] 67584K-63000K(98304K)]注意关键字Allocation Failure说明就是因为分配失败直接 Full GC 了没给你来一轮 Major GC 热身的机会。情况二CMS 收集器CMS 的处理方式就比较接近前面那个先后触发的理解了老年代使用达到阈值默认92% │ ▼ CMS 启动并发标记清除这个 ≈ Major GC │ ├── 成功 → 搞定程序继续跑 │ └── 失败Concurrent Mode Failure │ ▼ 退化为 Full GC整堆回收STWCMS 会在老年代还没完全满的时候就提前开始并发回收如果回收速度跟得上对象晋升的速度皆大欢喜。但如果跟不上老年代还是溢出了就会出现Concurrent Mode Failure然后退化成 Full GC。情况三G1 收集器G1 又是另一套逻辑。G1 把堆划分成了很多个 Region它不严格区分年轻代和老年代的单独回收Young GC回收年轻代 Region │ ▼ 并发标记后台标记老年代存活对象 │ ▼ Mixed GC同时回收年轻代 部分老年代 Region │ └── Mixed GC 也搞不定 → Full GC兜底G1 里你很少看到 Major GC 这个说法它用的是Mixed GC这个概念。万一 Mixed GC 也救不了场才会退化为 Full GC。总结一下这个关系用一张图说清楚老年代不足时触发什么 │ ├── Parallel / Serial ──→ 直接 Full GC │ ├── CMS ──→ 先并发回收老年代≈ Major GC │ └── 搞砸了 → Full GC │ └── G1 ──→ Mixed GC同时回收年轻代 部分老年代 Region └── 搞不定 → Full GC所以说Major GC 和 Full GC 的触发关系不是固定的它跟你选的收集器强相关。面试的时候如果你能把这一层说出来直接跟别人拉开差距。记忆技巧我自己的记忆方式分享一下Minor 小只扫年轻代这一小块地方。Major 大扫老年代这块大地方。Full 满/全全部扫一遍地毯式清理。或者你这样想Minor GC 每天倒垃圾桶随手的事Major GC 每周做一次大扫除稍微累点Full GC 搬家前的彻底清扫累死人而且你还不想太频繁搬家实战看看 GC 日志长啥样你在启动参数里加上 GC 日志就能看到这些信息JDK 8-XX:PrintGCDetails -XX:PrintGCDateStamps -Xloggc:gc.logJDK 9 及以上-Xlog:gc*:filegc.log:time,uptime,level,tags日志里看到类似这样的就是 Minor GC[GC (Allocation Failure) [PSYoungGen: 65536K-1024K(76288K)] 65536K-1025K(251392K), 0.005 secs]看到类似这样的就是 Full GC[Full GC (Ergonomics) [PSYoungGen: ...] [ParOldGen: ...] ...-...(...K), 0.08 secs]注意看关键字GC一般是 MinorFull GC明确写了 Full。多看几次日志你就熟悉了。还有几点容易踩的坑1. Minor GC 也会触发 Full GC不要觉得 Minor GC 就是小事。如果 Minor GC 后存活对象要晋升到老年代但老年代放不下就会触发 Full GC。所以老年代的空间规划很重要。2. 不要随便写System.gc()有些同学调试的时候喜欢加System.gc()这东西在生产环境就是个定时炸弹它会建议 JVM 做一次 Full GC。3. 不同垃圾收集器行为不一样G1 收集器里其实不太区分 Minor/Major GC它的概念是 Mixed GC。ZGC、Shenandoah 这些新收集器更是做到了几乎不感知的 GC 停顿。所以面试问你的时候你可以说传统分代收集器下有这三种区分然后补一句但 G1/ZGC 等新收集器有自己的 GC 阶段划分——这就很加分了。最后再来个总结新对象出生在 Eden │ Eden 满了 → Minor GC只扫年轻代快 │ 活下来的进 Survivor反复熬 │ 熬够次数 → 晋升老年代 │ 老年代满了 → 具体触发什么看收集器 │ ├── Parallel/Serial → Full GC │ ├── CMS → Major GC搞砸了再 Full GC │ └── G1 → Mixed GC搞不定再 Full GC │ 无论如何 → Full GC 都是最后的杀手锏尽量别让它出现理解了这条链路这三个概念你就彻底理清了。