前言
看 GC 日志和准备面试时,很多人总把 Young GC、Minor GC、Old GC、Major GC 和 Full GC 混在一起,甚至误以为所有收集器都会单独回收老年代。本文结合不同收集器的内存布局,把这几类 GC 的真实回收范围讲透。
文章目录
-
- 前言
- 一、堆内存怎么切分其实全看垃圾收集器的实现
-
- 1.1 经典收集器里的连续物理分代
- 1.2 G1收集器为什么要把连续内存打散成Region
- 二、专门清理新生代的Young GC与Minor GC
-
- 2.1 为什么所有收集器都要单独回收新生代
- 2.2 触发Young GC时的内存扫描范围
- 三、Old GC与Major GC最容易踩坑的认知误区
-
- 3.1 为什么目前只有CMS会单独回收老年代
- 3.2 其他收集器在老年代满了之后会怎么做
- 四、把整个堆翻个底朝天的Full GC
-
- 4.1 Full GC究竟回收了哪些内存区域
- 4.2 四种GC概念的对比与实战辨析
- 五、写在最后
一、堆内存怎么切分其实全看垃圾收集器的实现
前两篇我们聊堆内存时,一直按“新生代(Eden + 两个 Survivor)”和“老年代”的经典结构来画图。但我刚学 JVM 那会儿曾经产生过一个困惑,就是堆内存里的这些分代边界,到底是谁规定死的?
答案其实很简单。物理内存条上根本没有什么天生的“伊甸园”和“老年代”,那只是一整块连续的字节空间。堆内存具体怎么切分、每个区域长什么样,完全取决于你当前选用的**垃圾收集器(Garbage Collector)**怎么去实现它。
1.1 经典收集器里的连续物理分代
在 JDK 8 及以前最常用的经典分代收集器里,比如 Serial、ParNew、Parallel Scavenge 配合 Serial Old、Parallel Old 或 CMS,它们对堆内存的划分非常直观。
这些收集器在启动时,真的会在物理虚拟内存地址上划出两块壁垒分明、各自连续的内存空间:一块专门给新生代用,另一块专门给老年代用。
package com.crayontech.jvm;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryPoolMXBean;
public class HeapLayoutInspector {
public static void main(String[] args) {
System.out.println("=== 当前启用的垃圾收集器 ===");
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println("收集器名称: " + gcBean.getName()
+ " | 关联内存池: " + String.join(", ", gcBean.getMemoryPoolNames()));
}
System.out.println("\\n=== 堆内各逻辑内存池划分 ===");
for (MemoryPoolMXBean poolBean : ManagementFactory.getMemoryPoolMXBeans()) {
if ("Heap memory".equals(poolBean.getType().toString())) {
System.out.println("内存池: " + poolBean.getName());
}
}
}
}
你如果在启动参数里加上 -XX:+UseParallelGC 跑一下这段代码,就能看到 PS Eden Space、PS Survivor Space 和 PS Old Gen 这几个名字。在 Parallel Scavenge 收集器眼里,新生代就是一整块连续内存,老年代就是另一整块连续内存。
1.2 G1收集器为什么要把连续内存打散成Region
到了 JDK 9 默认启用的 G1(Garbage-First)收集器,情况就彻底变了。
G1 依然保留了新生代和老年代的逻辑概念,新创建的对象还是先去 Eden,熬过几次回收还是会去 Survivor 和老年代。但在底层内存布局上,G1 不再要求新生代或老年代是一整块连续的内存,而是把整个堆切成了几千个大小相等的独立块(Region)。
#mermaid-svg-BXbMJifNu4IEUV2q{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BXbMJifNu4IEUV2q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BXbMJifNu4IEUV2q .error-icon{fill:#552222;}#mermaid-svg-BXbMJifNu4IEUV2q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BXbMJifNu4IEUV2q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BXbMJifNu4IEUV2q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BXbMJifNu4IEUV2q .marker.cross{stroke:#333333;}#mermaid-svg-BXbMJifNu4IEUV2q svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BXbMJifNu4IEUV2q p{margin:0;}#mermaid-svg-BXbMJifNu4IEUV2q .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-BXbMJifNu4IEUV2q .cluster-label text{fill:#333;}#mermaid-svg-BXbMJifNu4IEUV2q .cluster-label span{color:#333;}#mermaid-svg-BXbMJifNu4IEUV2q .cluster-label span p{background-color:transparent;}#mermaid-svg-BXbMJifNu4IEUV2q .label text,#mermaid-svg-BXbMJifNu4IEUV2q span{fill:#333;color:#333;}#mermaid-svg-BXbMJifNu4IEUV2q .node rect,#mermaid-svg-BXbMJifNu4IEUV2q .node circle,#mermaid-svg-BXbMJifNu4IEUV2q .node ellipse,#mermaid-svg-BXbMJifNu4IEUV2q .node polygon,#mermaid-svg-BXbMJifNu4IEUV2q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BXbMJifNu4IEUV2q .rough-node .label text,#mermaid-svg-BXbMJifNu4IEUV2q .node .label text,#mermaid-svg-BXbMJifNu4IEUV2q .image-shape .label,#mermaid-svg-BXbMJifNu4IEUV2q .icon-shape .label{text-anchor:middle;}#mermaid-svg-BXbMJifNu4IEUV2q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BXbMJifNu4IEUV2q .rough-node .label,#mermaid-svg-BXbMJifNu4IEUV2q .node .label,#mermaid-svg-BXbMJifNu4IEUV2q .image-shape .label,#mermaid-svg-BXbMJifNu4IEUV2q .icon-shape .label{text-align:center;}#mermaid-svg-BXbMJifNu4IEUV2q .node.clickable{cursor:pointer;}#mermaid-svg-BXbMJifNu4IEUV2q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BXbMJifNu4IEUV2q .arrowheadPath{fill:#333333;}#mermaid-svg-BXbMJifNu4IEUV2q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BXbMJifNu4IEUV2q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BXbMJifNu4IEUV2q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BXbMJifNu4IEUV2q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BXbMJifNu4IEUV2q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BXbMJifNu4IEUV2q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BXbMJifNu4IEUV2q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BXbMJifNu4IEUV2q .cluster text{fill:#333;}#mermaid-svg-BXbMJifNu4IEUV2q .cluster span{color:#333;}#mermaid-svg-BXbMJifNu4IEUV2q div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BXbMJifNu4IEUV2q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BXbMJifNu4IEUV2q rect.text{fill:none;stroke-width:0;}#mermaid-svg-BXbMJifNu4IEUV2q .icon-shape,#mermaid-svg-BXbMJifNu4IEUV2q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BXbMJifNu4IEUV2q .icon-shape p,#mermaid-svg-BXbMJifNu4IEUV2q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BXbMJifNu4IEUV2q .icon-shape .label rect,#mermaid-svg-BXbMJifNu4IEUV2q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BXbMJifNu4IEUV2q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BXbMJifNu4IEUV2q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BXbMJifNu4IEUV2q :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
演进为化整为零的 Region 管理
G1 (Garbage-First) 收集器离散 Region 布局
Region 1(Eden)
Region 2(Old)
Region 3(Free 空闲)
Region 4(Survivor)
Region 5(Eden)
Region 6(Old)
经典分代收集器 (Serial / Parallel / CMS) 连续物理布局
Eden 区(连续物理内存块)
S0
S1
Old 老年代(连续物理内存块)
今天 1 号 Region 可能是 Eden 区,明天垃圾回收完清空了,它转身就能被分配成老年代 Region。理解了“不同垃圾收集器对新生代和老年代的管理方式不同”,再去理解各种 GC 词汇的差异就会顺畅得多。
二、专门清理新生代的Young GC与Minor GC
只要堆里划分出了新生代和老年代,垃圾收集器在干活时就得讲究策略。最常听到的两个词就是 Young GC(简称 YGC) 和 Minor GC。
很多人喜欢在文字游戏上纠结这两个词有什么细微差别。我直接给个明确结论:在实际工程排障和日常交流里,Young GC 和 Minor GC 指的就是同一件事,即专门针对新生代进行的垃圾回收,完全不需要把它们硬拆成两个概念。
2.1 为什么所有收集器都要单独回收新生代
不管是老牌的 Serial、ParNew、Parallel Scavenge,还是后来的 G1,几乎所有的分代垃圾收集器都专门设计了针对新生代单独触发的回收机制。
原因我们在上一篇聊对象分配时讲过:业务系统里 90% 以上的对象都是朝生夕死的临时变量。把火力集中在占堆内存比例较小的新生代,高频、快速地把死掉的对象清理掉,只把极少数活下来的对象拷进 Survivor 或晋升到老年代,这种做法的投入产出比最高。
2.2 触发Young GC时的内存扫描范围
当 Eden 区空间不足、没法为新对象分配内存时,收集器就会立刻拉响 Young GC 的警报。
老年代 Old 区
新生代 Survivor (S0/S1)
新生代 Eden 区
业务线程
老年代 Old 区
新生代 Survivor (S0/S1)
新生代 Eden 区
业务线程
#mermaid-svg-aLROtfqi4bg4OFUW{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aLROtfqi4bg4OFUW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aLROtfqi4bg4OFUW .error-icon{fill:#552222;}#mermaid-svg-aLROtfqi4bg4OFUW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aLROtfqi4bg4OFUW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aLROtfqi4bg4OFUW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aLROtfqi4bg4OFUW .marker.cross{stroke:#333333;}#mermaid-svg-aLROtfqi4bg4OFUW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aLROtfqi4bg4OFUW p{margin:0;}#mermaid-svg-aLROtfqi4bg4OFUW .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-aLROtfqi4bg4OFUW text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-aLROtfqi4bg4OFUW .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-aLROtfqi4bg4OFUW .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-aLROtfqi4bg4OFUW .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-aLROtfqi4bg4OFUW .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-aLROtfqi4bg4OFUW #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-aLROtfqi4bg4OFUW .sequenceNumber{fill:white;}#mermaid-svg-aLROtfqi4bg4OFUW #sequencenumber{fill:#333;}#mermaid-svg-aLROtfqi4bg4OFUW #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-aLROtfqi4bg4OFUW .messageText{fill:#333;stroke:none;}#mermaid-svg-aLROtfqi4bg4OFUW .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-aLROtfqi4bg4OFUW .labelText,#mermaid-svg-aLROtfqi4bg4OFUW .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-aLROtfqi4bg4OFUW .loopText,#mermaid-svg-aLROtfqi4bg4OFUW .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-aLROtfqi4bg4OFUW .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-aLROtfqi4bg4OFUW .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-aLROtfqi4bg4OFUW .noteText,#mermaid-svg-aLROtfqi4bg4OFUW .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-aLROtfqi4bg4OFUW .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-aLROtfqi4bg4OFUW .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-aLROtfqi4bg4OFUW .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-aLROtfqi4bg4OFUW .actorPopupMenu{position:absolute;}#mermaid-svg-aLROtfqi4bg4OFUW .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-aLROtfqi4bg4OFUW .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-aLROtfqi4bg4OFUW .actor-man circle,#mermaid-svg-aLROtfqi4bg4OFUW line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-aLROtfqi4bg4OFUW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Eden 剩余空间不足!
老年代内部不进行垃圾清理!
仅作为跨代引用根扫描及晋升接收方
清空 Eden 与 From Survivor,恢复业务线程
持续分配新对象
1
触发 Young GC (Minor GC)
2
扫描 Eden + From Survivor
将存活对象复制到 To Survivor
3
超龄或放不下的存活对象晋升老年代
4
注意看图里的边界:在一次纯粹的 Young GC 过程中,垃圾收集器只负责清理新生代(Eden 区和 From Survivor 区)里的垃圾对象,绝对不会顺手去把老年代里的垃圾对象也清理一遍。老年代在 Young GC 期间顶多接收一下从新生代晋升上来的对象,它自己肚子里的旧垃圾是原封不动的。
三、Old GC与Major GC最容易踩坑的认知误区
既然清理新生代叫 Young GC(或 Minor GC),那顺理成章地,清理老年代就叫做 Old GC 或者 Major GC。
从严格的定义上讲,Old GC / Major GC 指的就是只针对老年代进行的垃圾回收。但这个概念恰恰是最多人踩坑的地方。
3.1 为什么目前只有CMS会单独回收老年代
我以前面试候选人时常问一个问题:“你们线上用的是 Parallel Scavenge + Parallel Old 收集器,当老年代满了的时候,会触发一次只扫老年代的 Old GC 吗?”
很多人会毫不犹豫地点头说“会”。这就掉进文字陷阱里了。
在主流的经典分代垃圾收集器里,只有 CMS(Concurrent Mark Sweep)这一款收集器,拥有真正“单独对老年代进行垃圾回收”的机制!
package com.crayontech.jvm;
import java.util.ArrayList;
import java.util.List;
public class OldGenTriggerDemo {
private static final int ONE_MB = 1024 * 1024;
public static void main(String[] args) {
// 持续向集合添加长生命周期对象,促使其晋升并填满老年代
List<byte[]> oldGenCache = new ArrayList<>();
for (int i = 0; i < 30; i++) {
oldGenCache.add(new byte[2 * ONE_MB]);
}
System.out.println("缓存装载完成,当前持有块数: " + oldGenCache.size());
}
}
CMS 之所以特殊,是因为它本来就是一个专门只管老年代的并发收集器(通常搭配新生代的 ParNew 一起干活)。当老年代的使用率达到预设的阈值(比如通过 -XX:CMSInitiatingOccupancyFraction 设定的比例)时,CMS 就会单独启动一轮针对老年代的并发标记和清理。在这个过程中,它只回收老年代,这就是名副其实的 Old GC(Major GC)。
3.2 其他收集器在老年代满了之后会怎么做
那除了 CMS 之外,像我们最熟悉的 Parallel Old、Serial Old 这些收集器,为什么不单独做一次只针对老年代的垃圾回收呢?
因为对这些收集器来说,它们在设计上就没有把“老年代回收”拆成一个孤立执行的阶段。平时新生代满了,它们单独跑 Young GC;可一旦老年代也撑不住了、需要回收老年代的时候,它们的逻辑是:既然老年代这种重型区域都要停下来大扫除了,干脆把整个堆(包括新生代和老年代)全部一起扫一遍!
渲染错误: Mermaid 渲染失败: Parse error on line 4: … CheckGC –>|其他收集器 (Parallel Old / Seri ———————–^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
这就是为什么你在网上看技术文章或者看不同的监控工具时,会发现很多人把 Major GC 和 Full GC 混着叫。因为除了 CMS 之外,其他经典收集器根本不会单独回收老年代,只要动了老年代,实际干的就是整堆回收的活。
四、把整个堆翻个底朝天的Full GC
聊完了前面的概念,最后一个重量级选手 Full GC 就彻底清楚了。
Full GC 说白了就是整堆回收。
4.1 Full GC究竟回收了哪些内存区域
当 JVM 触发一次 Full GC 时,垃圾收集器不再区分什么伊甸园、幸存区还是老年代,它会把整个 Java 堆(新生代 + 老年代)以及方法区(元空间 Metaspace)翻个底朝天,找出所有区域里失去引用的垃圾对象,统统回收清理掉。
#mermaid-svg-lwlbgX43W5BSr2iW{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lwlbgX43W5BSr2iW .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lwlbgX43W5BSr2iW .error-icon{fill:#552222;}#mermaid-svg-lwlbgX43W5BSr2iW .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lwlbgX43W5BSr2iW .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lwlbgX43W5BSr2iW .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lwlbgX43W5BSr2iW .marker.cross{stroke:#333333;}#mermaid-svg-lwlbgX43W5BSr2iW svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lwlbgX43W5BSr2iW p{margin:0;}#mermaid-svg-lwlbgX43W5BSr2iW .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-lwlbgX43W5BSr2iW .cluster-label text{fill:#333;}#mermaid-svg-lwlbgX43W5BSr2iW .cluster-label span{color:#333;}#mermaid-svg-lwlbgX43W5BSr2iW .cluster-label span p{background-color:transparent;}#mermaid-svg-lwlbgX43W5BSr2iW .label text,#mermaid-svg-lwlbgX43W5BSr2iW span{fill:#333;color:#333;}#mermaid-svg-lwlbgX43W5BSr2iW .node rect,#mermaid-svg-lwlbgX43W5BSr2iW .node circle,#mermaid-svg-lwlbgX43W5BSr2iW .node ellipse,#mermaid-svg-lwlbgX43W5BSr2iW .node polygon,#mermaid-svg-lwlbgX43W5BSr2iW .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-lwlbgX43W5BSr2iW .rough-node .label text,#mermaid-svg-lwlbgX43W5BSr2iW .node .label text,#mermaid-svg-lwlbgX43W5BSr2iW .image-shape .label,#mermaid-svg-lwlbgX43W5BSr2iW .icon-shape .label{text-anchor:middle;}#mermaid-svg-lwlbgX43W5BSr2iW .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-lwlbgX43W5BSr2iW .rough-node .label,#mermaid-svg-lwlbgX43W5BSr2iW .node .label,#mermaid-svg-lwlbgX43W5BSr2iW .image-shape .label,#mermaid-svg-lwlbgX43W5BSr2iW .icon-shape .label{text-align:center;}#mermaid-svg-lwlbgX43W5BSr2iW .node.clickable{cursor:pointer;}#mermaid-svg-lwlbgX43W5BSr2iW .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-lwlbgX43W5BSr2iW .arrowheadPath{fill:#333333;}#mermaid-svg-lwlbgX43W5BSr2iW .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-lwlbgX43W5BSr2iW .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-lwlbgX43W5BSr2iW .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lwlbgX43W5BSr2iW .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-lwlbgX43W5BSr2iW .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lwlbgX43W5BSr2iW .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-lwlbgX43W5BSr2iW .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-lwlbgX43W5BSr2iW .cluster text{fill:#333;}#mermaid-svg-lwlbgX43W5BSr2iW .cluster span{color:#333;}#mermaid-svg-lwlbgX43W5BSr2iW div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-lwlbgX43W5BSr2iW .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-lwlbgX43W5BSr2iW rect.text{fill:none;stroke-width:0;}#mermaid-svg-lwlbgX43W5BSr2iW .icon-shape,#mermaid-svg-lwlbgX43W5BSr2iW .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-lwlbgX43W5BSr2iW .icon-shape p,#mermaid-svg-lwlbgX43W5BSr2iW .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-lwlbgX43W5BSr2iW .icon-shape .label rect,#mermaid-svg-lwlbgX43W5BSr2iW .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-lwlbgX43W5BSr2iW .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-lwlbgX43W5BSr2iW .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-lwlbgX43W5BSr2iW :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
JVM 内存回收范围全景
仅回收
仅回收
全量扫描并回收
全量扫描并回收
顺带卸载无用类
方法区 (Metaspace)
类元数据 / 常量池
老年代 (Old Gen)
Old 区
新生代 (Young Gen)
Eden
Survivor (S0 + S1)
Young GC / Minor GC
Old GC / Major GC(仅 CMS 独立支持)
Full GC (整堆回收)
因为老年代容量大、存活对象多,再加上还要连带处理新生代和元空间,Full GC 的停顿开销(Stop-The-World)往往是 Young GC 的十几倍甚至几十倍。线上系统如果几秒钟来一次 Young GC 属于家常便饭,但如果几分钟就来一次 Full GC,接口响应延迟肯定会飙升报警。
4.2 四种GC概念的对比与实战辨析
为了防止大家在看 GC 日志或面试答题时再绕晕,我把这几个概念的核心边界整理成了下面这张对照表:
| Young GC (YGC) | Minor GC | 只回收新生代(Eden + Survivor) | 所有分代收集器都会单独实现它,触发频率高、单次停顿时间短 |
| Old GC | Major GC | 只回收老年代(Old Generation) | 经典收集器里目前只有 CMS 会单独回收老年代;多数收集器无独立 Old GC |
| Full GC (FGC) | 整堆回收 | 整个堆(新生代 + 老年代)+ 方法区 | 除 CMS 外,其他收集器需要对老年代做回收时,基本都是直接触发整堆 Full GC |
| Mixed GC | 混合回收 | 全部新生代 + 部分老年代 Region | G1 收集器特有:挑选垃圾比例最高的老年代 Region 与新生代一起回收 |
看这张表就能明白,以后有人问你 Major GC 和 Full GC 有什么区别,你千万别只背一句“Major GC 回收老年代,Full GC 回收整个堆”。
更地道的回答是:先把概念定义分开,再立刻补上一句**“目前经典收集器里只有 CMS 会单独对老年代做 Old GC,其他大多数收集器并不会单独回收老年代,而是在需要回收老年代时直接触发整堆范围的 Full GC”**。这一句话点出来,面试官立刻就知道你真正在工程层面琢磨过收集器的运行机制。
五、写在最后
把 Young GC、Minor GC、Old GC、Major GC 和 Full GC 摆在一起看,核心其实就是一条主线:新生代垃圾多、死得快,所以所有收集器都愿意单独为它开小灶做高频的 Young GC;而老年代体积大、对象硬,除了 CMS 专门做了并发的单区回收外,大多数收集器一旦决定动老年代,干脆就拉着新生代一起做一次彻底的 Full GC 大扫除。
如果这篇文章帮你理清了这几个容易混淆的 GC 概念,别忘了给作者点个关注,下一篇我们继续顺着这条线往下深挖 JVM 的垃圾回收机制。


