【从0到1学习JVM · 14】堆内存各区域分工与Xms和Xmx设为一样的真相

前言

很多人刚接触 JVM 内存模型时,最先听说的往往是堆区。规范里写得很明白,几乎所有的对象和数组都要分配在堆里。但堆具体长什么样、里面各区域怎么配合,生产配置参数又藏着哪些门道,不少人其实没有深究过。本文就把堆的内部结构与核心参数一次性拆解清楚。


文章目录

一、对象在堆里而引用在栈里

写 Java 代码的时候,创建对象就像呼吸一样自然:

java 复制代码
package com.crayontech.jvm;

public class HeapMemoryDemo {
    public void processTask() {
        Order order = new Order();
        order.execute();
    }
}

表面看只有短短两行代码,但在 JVM 底层,它其实跨越了两个完全不同的内存空间。

前面讲执行引擎和虚拟机栈时我们知道,当线程调用 processTask 方法时,JVM 会为它在虚拟机栈里压入一个栈帧。这个栈帧里的局部变量表会分配一个 Slot,用来存放变量 order。

但这个 Slot 里存的并不是真正的订单对象,而仅仅是一个内存引用地址 (Reference)。真正的 Order 实例对象,是在堆(Heap)里面开辟空间存放的。
#mermaid-svg-5Y3FZfVkhPTzWEWM{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-5Y3FZfVkhPTzWEWM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5Y3FZfVkhPTzWEWM .error-icon{fill:#552222;}#mermaid-svg-5Y3FZfVkhPTzWEWM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5Y3FZfVkhPTzWEWM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .marker.cross{stroke:#333333;}#mermaid-svg-5Y3FZfVkhPTzWEWM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5Y3FZfVkhPTzWEWM p{margin:0;}#mermaid-svg-5Y3FZfVkhPTzWEWM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster-label text{fill:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster-label span{color:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster-label span p{background-color:transparent;}#mermaid-svg-5Y3FZfVkhPTzWEWM .label text,#mermaid-svg-5Y3FZfVkhPTzWEWM span{fill:#333;color:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .node rect,#mermaid-svg-5Y3FZfVkhPTzWEWM .node circle,#mermaid-svg-5Y3FZfVkhPTzWEWM .node ellipse,#mermaid-svg-5Y3FZfVkhPTzWEWM .node polygon,#mermaid-svg-5Y3FZfVkhPTzWEWM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .rough-node .label text,#mermaid-svg-5Y3FZfVkhPTzWEWM .node .label text,#mermaid-svg-5Y3FZfVkhPTzWEWM .image-shape .label,#mermaid-svg-5Y3FZfVkhPTzWEWM .icon-shape .label{text-anchor:middle;}#mermaid-svg-5Y3FZfVkhPTzWEWM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .rough-node .label,#mermaid-svg-5Y3FZfVkhPTzWEWM .node .label,#mermaid-svg-5Y3FZfVkhPTzWEWM .image-shape .label,#mermaid-svg-5Y3FZfVkhPTzWEWM .icon-shape .label{text-align:center;}#mermaid-svg-5Y3FZfVkhPTzWEWM .node.clickable{cursor:pointer;}#mermaid-svg-5Y3FZfVkhPTzWEWM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .arrowheadPath{fill:#333333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5Y3FZfVkhPTzWEWM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5Y3FZfVkhPTzWEWM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5Y3FZfVkhPTzWEWM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster text{fill:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM .cluster span{color:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM 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-5Y3FZfVkhPTzWEWM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5Y3FZfVkhPTzWEWM rect.text{fill:none;stroke-width:0;}#mermaid-svg-5Y3FZfVkhPTzWEWM .icon-shape,#mermaid-svg-5Y3FZfVkhPTzWEWM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5Y3FZfVkhPTzWEWM .icon-shape p,#mermaid-svg-5Y3FZfVkhPTzWEWM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5Y3FZfVkhPTzWEWM .icon-shape .label rect,#mermaid-svg-5Y3FZfVkhPTzWEWM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5Y3FZfVkhPTzWEWM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5Y3FZfVkhPTzWEWM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5Y3FZfVkhPTzWEWM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 线程共享:堆内存 (Heap)
线程私有:虚拟机栈
processTask 方法栈帧
持有内存指针
局部变量表: Slot 1 (order 引用地址 0x7A0012)
Order 对象实体 (0x7A0012)

  • 对象头 (Mark Word + Klass Word)

  • 实例数据 (orderId, amount...)

  • 对齐填充

1.1 方法退栈后对象为什么不立刻消失

这里有一个刚学 JVM 时容易混淆的细节:方法执行完了,这个对象会立刻被销毁吗?

答案是不会。

当 processTask 执行完毕,方法对应的栈帧会瞬间出栈并销毁。随着栈顶指针回退,局部变量表里的 order 引用直接失效。但是,堆内存里的那个 Order 对象实体依然安安静静地躺在堆空间里。

因为虚拟机栈只管当前线程的方法调用生命周期,而堆是所有线程共享的公用内存池。JVM 设计者不可能让一个线程在方法退出时,还专门停下来去堆里把刚才用过的对象立刻抹除。真要这么做,方法调用的开销就太大了。

堆中的对象什么时候清理,完全由专门的**垃圾收集器(Garbage Collector,简称 GC)**在后台异步扫描并决定。只要对象不再被任何存活的引用关联,它就会在后续的 GC 周期里被回收释放。

二、生产环境为什么必须把Xms和Xmx配成一样

既然堆要承载系统中绝大部分对象,那这块空间到底有多大?

JVM 提供了两个最基础的堆内存配置参数:

  • -Xms:全称是 Memory Start,表示堆的初始分配内存大小 ,等价于 -XX:InitialHeapSize。
  • -Xmx:全称是 Memory Max,表示堆所允许使用的最大内存上限 ,等价于 -XX:MaxHeapSize。

如果不做任何手动配置,JVM 在启动时会根据宿主机的物理内存自动推算默认值:初始内存通常是宿主机物理内存的 1/64 左右,最大内存通常是物理内存的 1/4 左右。

2.1 堆内存的默认扩缩容机制

在未显式把两个参数设为相等的情况下,堆内存是具有弹性的。

JVM 启动时,只会先向操作系统申请 -Xms 指定的内存。随着业务运行,新的对象源源不断被创建,一旦当前的堆空间不够用了,JVM 就会触发 GC。如果 GC 之后可用空间依然吃紧,JVM 就会主动向操作系统申请扩展内存,直到达到 -Xmx 规定的上限。

反过来,如果经过某次大范围垃圾回收后,堆里的空闲率过高,JVM 还会尝试把一部分内存退还给操作系统。

听起来这个动态弹性机制非常智能,既不浪费宿主机内存,又能按需索取。但在高并发的生产环境中,这种设计往往是性能杀手。
#mermaid-svg-voeJWkjGrl4pOSMl{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-voeJWkjGrl4pOSMl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-voeJWkjGrl4pOSMl .error-icon{fill:#552222;}#mermaid-svg-voeJWkjGrl4pOSMl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-voeJWkjGrl4pOSMl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-voeJWkjGrl4pOSMl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-voeJWkjGrl4pOSMl .marker.cross{stroke:#333333;}#mermaid-svg-voeJWkjGrl4pOSMl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-voeJWkjGrl4pOSMl p{margin:0;}#mermaid-svg-voeJWkjGrl4pOSMl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-voeJWkjGrl4pOSMl .cluster-label text{fill:#333;}#mermaid-svg-voeJWkjGrl4pOSMl .cluster-label span{color:#333;}#mermaid-svg-voeJWkjGrl4pOSMl .cluster-label span p{background-color:transparent;}#mermaid-svg-voeJWkjGrl4pOSMl .label text,#mermaid-svg-voeJWkjGrl4pOSMl span{fill:#333;color:#333;}#mermaid-svg-voeJWkjGrl4pOSMl .node rect,#mermaid-svg-voeJWkjGrl4pOSMl .node circle,#mermaid-svg-voeJWkjGrl4pOSMl .node ellipse,#mermaid-svg-voeJWkjGrl4pOSMl .node polygon,#mermaid-svg-voeJWkjGrl4pOSMl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-voeJWkjGrl4pOSMl .rough-node .label text,#mermaid-svg-voeJWkjGrl4pOSMl .node .label text,#mermaid-svg-voeJWkjGrl4pOSMl .image-shape .label,#mermaid-svg-voeJWkjGrl4pOSMl .icon-shape .label{text-anchor:middle;}#mermaid-svg-voeJWkjGrl4pOSMl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-voeJWkjGrl4pOSMl .rough-node .label,#mermaid-svg-voeJWkjGrl4pOSMl .node .label,#mermaid-svg-voeJWkjGrl4pOSMl .image-shape .label,#mermaid-svg-voeJWkjGrl4pOSMl .icon-shape .label{text-align:center;}#mermaid-svg-voeJWkjGrl4pOSMl .node.clickable{cursor:pointer;}#mermaid-svg-voeJWkjGrl4pOSMl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-voeJWkjGrl4pOSMl .arrowheadPath{fill:#333333;}#mermaid-svg-voeJWkjGrl4pOSMl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-voeJWkjGrl4pOSMl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-voeJWkjGrl4pOSMl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-voeJWkjGrl4pOSMl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-voeJWkjGrl4pOSMl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-voeJWkjGrl4pOSMl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-voeJWkjGrl4pOSMl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-voeJWkjGrl4pOSMl .cluster text{fill:#333;}#mermaid-svg-voeJWkjGrl4pOSMl .cluster span{color:#333;}#mermaid-svg-voeJWkjGrl4pOSMl 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-voeJWkjGrl4pOSMl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-voeJWkjGrl4pOSMl rect.text{fill:none;stroke-width:0;}#mermaid-svg-voeJWkjGrl4pOSMl .icon-shape,#mermaid-svg-voeJWkjGrl4pOSMl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-voeJWkjGrl4pOSMl .icon-shape p,#mermaid-svg-voeJWkjGrl4pOSMl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-voeJWkjGrl4pOSMl .icon-shape .label rect,#mermaid-svg-voeJWkjGrl4pOSMl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-voeJWkjGrl4pOSMl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-voeJWkjGrl4pOSMl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-voeJWkjGrl4pOSMl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 生产推荐锁定堆 (-Xms == -Xmx)
业务请求激增
内存早已一次性分配就绪
零扩容系统调用开销
平稳运行,资源全力供给业务代码
动态伸缩堆 (-Xms < -Xmx)
业务请求激增
堆空间不足
触发垃圾回收与停顿
向操作系统申请扩容系统调用
发生内存抖动与接口响应毛刺

2.2 频繁扩缩容带来的性能抖动与开销

我一直建议:在正式的生产环境中,必须无条件把 -Xms 和 -Xmx 设置为完全相同的数值。

原因其实非常纯粹:

向操作系统申请内存和归还内存,从来都不是免费的午餐。每次堆内存扩容,JVM 都需要发起底层的系统调用,重新划分内存页表与地址空间。伴随这个过程的,往往是更频繁的 Full GC 和更漫长的心跳停顿。

如果一个 Java 服务的堆在 2GB 到 8GB 之间反复横跳,不仅 CPU 资源会被频繁的内存伸缩和 GC 标记挤占,还会让外部监控观察到严重的请求延迟毛刺。

把 -Xms 和 -Xmx 设为一样大(比如同时配成 -Xms8g -Xmx8g),JVM 在进程启动那一刻就会向操作系统一次性锁定这 8GB 的物理连续空间。之后整个运行期内,堆大小固定不变,彻底杜绝了动态调整内存带来的额外消耗。

当然,如果对象分配速度彻底失控,把整个 -Xmx 撑爆了且 GC 回天乏术,JVM 就会毫不留情地抛出我们熟悉的堆溢出错误:

text 复制代码
java.lang.OutOfMemoryError: Java heap space

三、堆内存为什么非要分代

看清楚了堆的大小控制,我们再来看堆内部的构造。

如果让你来设计堆内存,最简单的方案莫过于把整块堆当成一个大蓄水池:对象来了就往里填,内存满了就做一次全盘大扫除。

但 JVM 团队没有这么做。在主流的 HotSpot 虚拟机里,堆被严格切分成了新生代(Young Generation)和老年代(Old Generation)。

为什么要搞得这么麻烦?
#mermaid-svg-5w2zqONcZKY2sJqo{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-5w2zqONcZKY2sJqo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5w2zqONcZKY2sJqo .error-icon{fill:#552222;}#mermaid-svg-5w2zqONcZKY2sJqo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5w2zqONcZKY2sJqo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5w2zqONcZKY2sJqo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5w2zqONcZKY2sJqo .marker.cross{stroke:#333333;}#mermaid-svg-5w2zqONcZKY2sJqo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5w2zqONcZKY2sJqo p{margin:0;}#mermaid-svg-5w2zqONcZKY2sJqo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5w2zqONcZKY2sJqo .cluster-label text{fill:#333;}#mermaid-svg-5w2zqONcZKY2sJqo .cluster-label span{color:#333;}#mermaid-svg-5w2zqONcZKY2sJqo .cluster-label span p{background-color:transparent;}#mermaid-svg-5w2zqONcZKY2sJqo .label text,#mermaid-svg-5w2zqONcZKY2sJqo span{fill:#333;color:#333;}#mermaid-svg-5w2zqONcZKY2sJqo .node rect,#mermaid-svg-5w2zqONcZKY2sJqo .node circle,#mermaid-svg-5w2zqONcZKY2sJqo .node ellipse,#mermaid-svg-5w2zqONcZKY2sJqo .node polygon,#mermaid-svg-5w2zqONcZKY2sJqo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5w2zqONcZKY2sJqo .rough-node .label text,#mermaid-svg-5w2zqONcZKY2sJqo .node .label text,#mermaid-svg-5w2zqONcZKY2sJqo .image-shape .label,#mermaid-svg-5w2zqONcZKY2sJqo .icon-shape .label{text-anchor:middle;}#mermaid-svg-5w2zqONcZKY2sJqo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5w2zqONcZKY2sJqo .rough-node .label,#mermaid-svg-5w2zqONcZKY2sJqo .node .label,#mermaid-svg-5w2zqONcZKY2sJqo .image-shape .label,#mermaid-svg-5w2zqONcZKY2sJqo .icon-shape .label{text-align:center;}#mermaid-svg-5w2zqONcZKY2sJqo .node.clickable{cursor:pointer;}#mermaid-svg-5w2zqONcZKY2sJqo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5w2zqONcZKY2sJqo .arrowheadPath{fill:#333333;}#mermaid-svg-5w2zqONcZKY2sJqo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5w2zqONcZKY2sJqo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5w2zqONcZKY2sJqo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5w2zqONcZKY2sJqo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5w2zqONcZKY2sJqo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5w2zqONcZKY2sJqo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5w2zqONcZKY2sJqo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5w2zqONcZKY2sJqo .cluster text{fill:#333;}#mermaid-svg-5w2zqONcZKY2sJqo .cluster span{color:#333;}#mermaid-svg-5w2zqONcZKY2sJqo 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-5w2zqONcZKY2sJqo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5w2zqONcZKY2sJqo rect.text{fill:none;stroke-width:0;}#mermaid-svg-5w2zqONcZKY2sJqo .icon-shape,#mermaid-svg-5w2zqONcZKY2sJqo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5w2zqONcZKY2sJqo .icon-shape p,#mermaid-svg-5w2zqONcZKY2sJqo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5w2zqONcZKY2sJqo .icon-shape .label rect,#mermaid-svg-5w2zqONcZKY2sJqo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5w2zqONcZKY2sJqo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5w2zqONcZKY2sJqo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5w2zqONcZKY2sJqo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 堆内存划分 (默认比例 1 : 2)
新生代 (Young Gen)

占比: 1/3

存放朝生夕灭的新生对象
老年代 (Old Gen)

占比: 2/3

存放长期存活与大对象

3.1 绝大多数对象朝生夕灭的统计学规律

分代设计的理论基石,是著名的弱分代假说(Weak Generational Hypothesis)。

工程师们经过大量实际工程统计发现:在运行的 Java 系统中,超过 90% 的对象都是朝生夕灭的。

想想平时写的方法:

java 复制代码
package com.crayontech.jvm;

import java.util.HashMap;
import java.util.Map;

public class TemporaryObjectDemo {
    public String buildJsonResponse(long id, String name) {
        // map 和内部的 key、value 对象仅在当前方法内部存活
        Map<String, Object> data = new HashMap<>();
        data.put("id", id);
        data.put("name", name);
        return data.toString();
    }
}

每次调用 buildJsonResponse,方法里创建的 HashMap 实例只用来做数据转换。一旦方法返回,这些临时对象在下一毫秒就彻底失去了被引用的价值。

只有极少数对象能够长命百岁:比如 Spring 容器里的单例 Bean、全局数据库连接池、系统常驻缓存。

如果把朝生夕灭的临时工和长命百岁的老员工混在一起存,每次垃圾回收就必须把几十个 G 的整个堆内存全部扫描一遍。这种无差别全量扫描对系统吞吐量来说是灾难性的。

分代之后,GC 的思路立刻清晰了:

  • 对新生代采用高频、快速的局部回收(Minor GC / Young GC),专门清理那些刚生下来就死掉的短命鬼;
  • 对老年代采用低频稳健的回收策略(Major GC / Full GC),不用每次都去打扰那些长期存活的老对象。

3.2 新生代与老年代的比例划分规则

既然分了新生代和老年代,那各自该占多大地盘?

JVM 提供了 -XX:NewRatio 参数来配置老年代与新生代的比例,默认值是 2。

这里要看清比例的方向:

  • NewRatio=2 表示的是 老年代 : 新生代 = 2 : 1。
  • 换句话说,新生代占据了整个堆空间的 1/3 ,而老年代占据了整个堆空间的 2/3。

老年代的地盘明显比新生代大得多。这也是符合工程常识的:老年代里积攒的都是历经多次 GC 依然幸存的硬骨头,而且没有备用缓冲区,必须预留足够的空间作为安全水位,防止突发流量直接冲垮老年代。

四、新生代里为什么需要两个幸存者区

把目光聚焦到新生代内部,你会发现设计者在这里玩出了更精妙的花样。

新生代内部细分成了三个部分:

  1. Eden 区(伊甸园区):新对象降生的地方;
  2. From Survivor 区(S0,幸存者 0 区);
  3. To Survivor 区(S1,幸存者 1 区)。

#mermaid-svg-Yyw5Tq7tpXVavdoA{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-Yyw5Tq7tpXVavdoA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Yyw5Tq7tpXVavdoA .error-icon{fill:#552222;}#mermaid-svg-Yyw5Tq7tpXVavdoA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Yyw5Tq7tpXVavdoA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .marker.cross{stroke:#333333;}#mermaid-svg-Yyw5Tq7tpXVavdoA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Yyw5Tq7tpXVavdoA p{margin:0;}#mermaid-svg-Yyw5Tq7tpXVavdoA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster-label text{fill:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster-label span{color:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster-label span p{background-color:transparent;}#mermaid-svg-Yyw5Tq7tpXVavdoA .label text,#mermaid-svg-Yyw5Tq7tpXVavdoA span{fill:#333;color:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .node rect,#mermaid-svg-Yyw5Tq7tpXVavdoA .node circle,#mermaid-svg-Yyw5Tq7tpXVavdoA .node ellipse,#mermaid-svg-Yyw5Tq7tpXVavdoA .node polygon,#mermaid-svg-Yyw5Tq7tpXVavdoA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .rough-node .label text,#mermaid-svg-Yyw5Tq7tpXVavdoA .node .label text,#mermaid-svg-Yyw5Tq7tpXVavdoA .image-shape .label,#mermaid-svg-Yyw5Tq7tpXVavdoA .icon-shape .label{text-anchor:middle;}#mermaid-svg-Yyw5Tq7tpXVavdoA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .rough-node .label,#mermaid-svg-Yyw5Tq7tpXVavdoA .node .label,#mermaid-svg-Yyw5Tq7tpXVavdoA .image-shape .label,#mermaid-svg-Yyw5Tq7tpXVavdoA .icon-shape .label{text-align:center;}#mermaid-svg-Yyw5Tq7tpXVavdoA .node.clickable{cursor:pointer;}#mermaid-svg-Yyw5Tq7tpXVavdoA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .arrowheadPath{fill:#333333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Yyw5Tq7tpXVavdoA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Yyw5Tq7tpXVavdoA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Yyw5Tq7tpXVavdoA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster text{fill:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA .cluster span{color:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA 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-Yyw5Tq7tpXVavdoA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Yyw5Tq7tpXVavdoA rect.text{fill:none;stroke-width:0;}#mermaid-svg-Yyw5Tq7tpXVavdoA .icon-shape,#mermaid-svg-Yyw5Tq7tpXVavdoA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Yyw5Tq7tpXVavdoA .icon-shape p,#mermaid-svg-Yyw5Tq7tpXVavdoA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Yyw5Tq7tpXVavdoA .icon-shape .label rect,#mermaid-svg-Yyw5Tq7tpXVavdoA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Yyw5Tq7tpXVavdoA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Yyw5Tq7tpXVavdoA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Yyw5Tq7tpXVavdoA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 新生代内部结构 (8 : 1 : 1)
Eden 伊甸园区 (80%)

绝大部分新对象诞生于此
Survivor 0 / From (10%)

存放存活下来的幸存对象
Survivor 1 / To (10%)

GC 时作为空的接收容器

4.1 8比1比1的黄金比例

新生代各个区域的大小比例由 -XX:SurvivorRatio 控制,默认参数是 8。

这个配置意味着:

  • Eden : Survivor 0 : Survivor 1 = 8 : 1 : 1。
  • Eden 区独占新生代总容量的 80%;
  • 两个 Survivor 区各占新生代总容量的 10%。

让 Eden 独占八成空间,同样是顺应了前面提到的统计学规律:既然绝大多数对象很快就会消亡,那就给"生产车间"留出最大面积,让对象尽管创建。

4.2 From与To轮转如何彻底解决内存碎片

很多同学最大的困惑在于:既然叫幸存者区,留一个不就行了吗?为什么一定要设计成两个 Survivor 区(S0 和 S1)?

答案只有四个字:内存碎片。

假设只有一个 Survivor 区,看看会发生什么情况:

Eden 空间满了,触发 Minor GC,把活下来的少量对象搬运到唯一的那块 Survivor 区。接着系统继续运行,Eden 又满了,Survivor 里的对象也有一部分死掉了。

此时如果你想清理 Survivor,你就得在原地把死掉的对象挖掉。可这样一来,Survivor 内存里就会留下密密麻麻的空洞和碎片。当下一次再有稍微大一点的存活对象想塞进来时,就会因为找不到连续的物理空间而提前报错。

为了彻底消除碎片,JVM 在新生代采用了经典的标记-复制算法(Copying Algorithm)。

两个 Survivor 区轮流扮演角色,一个当 From ,一个当 To:

  • 核心规矩 :无论何时,To 区必须时刻保持完全空闲。
  • 当 Eden 区满了触发 Minor GC 时,垃圾回收器会把 Eden 区里依然存活的对象,连同当前那个 From 区里依然存活的对象,一口气整整齐齐地复制到空的 To 区里。
  • 复制完成后,Eden 区和原先的 From 区瞬间被整体清空,变成一张白纸。
  • 最后,刚才装满对象的 To 区摇身一变成为新的 From 区,原先清空的 From 区则变成下一次 GC 专用的 To 区。

To Survivor (S1,初始为空) From Survivor (S0) Eden 区 (80%) To Survivor (S1,初始为空) From Survivor (S0) Eden 区 (80%) #mermaid-svg-L79PRXG6ZfUZjRTO{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-L79PRXG6ZfUZjRTO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-L79PRXG6ZfUZjRTO .error-icon{fill:#552222;}#mermaid-svg-L79PRXG6ZfUZjRTO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-L79PRXG6ZfUZjRTO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-L79PRXG6ZfUZjRTO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-L79PRXG6ZfUZjRTO .marker.cross{stroke:#333333;}#mermaid-svg-L79PRXG6ZfUZjRTO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-L79PRXG6ZfUZjRTO p{margin:0;}#mermaid-svg-L79PRXG6ZfUZjRTO .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L79PRXG6ZfUZjRTO text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-L79PRXG6ZfUZjRTO .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-L79PRXG6ZfUZjRTO .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-L79PRXG6ZfUZjRTO #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-L79PRXG6ZfUZjRTO .sequenceNumber{fill:white;}#mermaid-svg-L79PRXG6ZfUZjRTO #sequencenumber{fill:#333;}#mermaid-svg-L79PRXG6ZfUZjRTO #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-L79PRXG6ZfUZjRTO .messageText{fill:#333;stroke:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L79PRXG6ZfUZjRTO .labelText,#mermaid-svg-L79PRXG6ZfUZjRTO .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .loopText,#mermaid-svg-L79PRXG6ZfUZjRTO .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .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-L79PRXG6ZfUZjRTO .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-L79PRXG6ZfUZjRTO .noteText,#mermaid-svg-L79PRXG6ZfUZjRTO .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-L79PRXG6ZfUZjRTO .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L79PRXG6ZfUZjRTO .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L79PRXG6ZfUZjRTO .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-L79PRXG6ZfUZjRTO .actorPopupMenu{position:absolute;}#mermaid-svg-L79PRXG6ZfUZjRTO .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-L79PRXG6ZfUZjRTO .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-L79PRXG6ZfUZjRTO .actor-man circle,#mermaid-svg-L79PRXG6ZfUZjRTO line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-L79PRXG6ZfUZjRTO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 触发 Minor GC 前:Eden 放满,S0 有上一轮存活对象 彻底清空 Eden 与 From 角色互换:S1 变成新 From,S0 变成新 To 复制 Eden 中存活对象(紧凑排列) 1 复制 From 中仍存活对象(年龄+1) 2 重置为空白内存 3 重置为空白内存 4

通过这套犹如杂耍般的轮转交替,新生代不仅清理速度极快,而且每次复制过去的对象都是首尾相连紧凑排列的,连一个字节的内存碎片都不会产生。

4.3 对象从出生到进入老年代的完整流转

把上面讲的所有区域串联起来,一个 Java 对象从创建到晋升老年代的完整生命历程是这样的:

  1. 出生降临 :绝大多数对象在 new 出来后,首先被分配在 Eden 区。
  2. 初次大浪淘沙:当 Eden 区快满时,触发一次 Minor GC。绝大部分短命对象直接在 Eden 里阵亡;少数命硬活下来的,被打包复制到 To 区,对象的年龄计数器(Age)被标记为 1。
  3. Survivor 之间倒腾:之后系统继续运行,每经历一次 Minor GC,存活对象的年龄就会递增 1 岁。
  4. 晋升老年代 :当一个对象的年龄增长到阈值(默认是 15 岁,通过 -XX:MaxTenuringThreshold 设定)时,JVM 就会认为它是个长命对象,正式把它晋升(Promote)到老年代常驻。
  5. 大对象特权通道 :如果一个对象体积极其庞大(比如分配了一个巨大的长字节数组),如果让它在 Eden 和两个 Survivor 之间来回倒腾复制,性能损耗会非常惊人。JVM 允许通过 -XX:PretenureSizeThreshold 参数设定阈值,一旦对象大小超过这个值,会直接跳过新生代,直接在老年代开辟空间。

#mermaid-svg-Palc4azz2RSvKe9b{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-Palc4azz2RSvKe9b .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Palc4azz2RSvKe9b .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Palc4azz2RSvKe9b .error-icon{fill:#552222;}#mermaid-svg-Palc4azz2RSvKe9b .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Palc4azz2RSvKe9b .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Palc4azz2RSvKe9b .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Palc4azz2RSvKe9b .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Palc4azz2RSvKe9b .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Palc4azz2RSvKe9b .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Palc4azz2RSvKe9b .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Palc4azz2RSvKe9b .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Palc4azz2RSvKe9b .marker.cross{stroke:#333333;}#mermaid-svg-Palc4azz2RSvKe9b svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Palc4azz2RSvKe9b p{margin:0;}#mermaid-svg-Palc4azz2RSvKe9b .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Palc4azz2RSvKe9b .cluster-label text{fill:#333;}#mermaid-svg-Palc4azz2RSvKe9b .cluster-label span{color:#333;}#mermaid-svg-Palc4azz2RSvKe9b .cluster-label span p{background-color:transparent;}#mermaid-svg-Palc4azz2RSvKe9b .label text,#mermaid-svg-Palc4azz2RSvKe9b span{fill:#333;color:#333;}#mermaid-svg-Palc4azz2RSvKe9b .node rect,#mermaid-svg-Palc4azz2RSvKe9b .node circle,#mermaid-svg-Palc4azz2RSvKe9b .node ellipse,#mermaid-svg-Palc4azz2RSvKe9b .node polygon,#mermaid-svg-Palc4azz2RSvKe9b .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Palc4azz2RSvKe9b .rough-node .label text,#mermaid-svg-Palc4azz2RSvKe9b .node .label text,#mermaid-svg-Palc4azz2RSvKe9b .image-shape .label,#mermaid-svg-Palc4azz2RSvKe9b .icon-shape .label{text-anchor:middle;}#mermaid-svg-Palc4azz2RSvKe9b .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Palc4azz2RSvKe9b .rough-node .label,#mermaid-svg-Palc4azz2RSvKe9b .node .label,#mermaid-svg-Palc4azz2RSvKe9b .image-shape .label,#mermaid-svg-Palc4azz2RSvKe9b .icon-shape .label{text-align:center;}#mermaid-svg-Palc4azz2RSvKe9b .node.clickable{cursor:pointer;}#mermaid-svg-Palc4azz2RSvKe9b .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Palc4azz2RSvKe9b .arrowheadPath{fill:#333333;}#mermaid-svg-Palc4azz2RSvKe9b .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Palc4azz2RSvKe9b .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Palc4azz2RSvKe9b .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Palc4azz2RSvKe9b .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Palc4azz2RSvKe9b .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Palc4azz2RSvKe9b .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Palc4azz2RSvKe9b .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Palc4azz2RSvKe9b .cluster text{fill:#333;}#mermaid-svg-Palc4azz2RSvKe9b .cluster span{color:#333;}#mermaid-svg-Palc4azz2RSvKe9b 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-Palc4azz2RSvKe9b .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Palc4azz2RSvKe9b rect.text{fill:none;stroke-width:0;}#mermaid-svg-Palc4azz2RSvKe9b .icon-shape,#mermaid-svg-Palc4azz2RSvKe9b .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Palc4azz2RSvKe9b .icon-shape p,#mermaid-svg-Palc4azz2RSvKe9b .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Palc4azz2RSvKe9b .icon-shape .label rect,#mermaid-svg-Palc4azz2RSvKe9b .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Palc4azz2RSvKe9b .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Palc4azz2RSvKe9b .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Palc4azz2RSvKe9b :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
否
是
否
是
是
否
new 创建对象
对象是否超过大对象阈值?
直接在老年代 (Old Gen) 分配
在 Eden 区分配
Eden 空间是否已满?
正常运行
触发 Minor GC (Young GC)
对象是否仍然存活?
直接回收释放
复制到 To Survivor 区,年龄 +1
年龄是否达到 15 岁阈值?
晋升到老年代 (Old Gen)
留在 Survivor 区等待下一次轮转

五、写在最后

回过头来看 JVM 堆的结构设计,它其实是计算机科学中"用空间换时间、按统计学概率做特化优化"的典范:

它没有把内存当成均匀的一整块铁板,而是敏锐地捕捉到了绝大多数对象活不过几次方法调用的客观规律。通过新生代与老年代的二八分化,再配合 Survivor 区的 From/To 轮转复制,JVM 用极小的 GC 停顿代价,换取了支撑超高并发吞吐量的底气。

而在实际线上部署时,主动把 -Xms 和 -Xmx 锁死为相同大小,更是每一位后端开发都应当刻进骨子里的工程自觉。

如果你觉得本文把堆的结构分工与配置细节讲透了,记得点个关注。后续文章我们会继续顺着这套内存架构,深入拆解对象在内存里的真实排布、指针压缩与垃圾回收器的并发标记细节。

相关推荐
東隅已逝,桑榆非晚1 小时前
stack和queue(类函数学习和模拟实现)
c++·笔记·学习
HwJack201 小时前
【HarmonyOS开发小实践】HarmonyOS GC 引用计数 vs 对象追踪,三种回收算法
jvm·算法·harmonyos
.道阻且长.1 小时前
C++11 :右值引用的作用,引用折叠和完美转发
java·开发语言·c++
code2cat1 小时前
Java进阶篇之StampedLock:先读取,再校验,必要时退回读锁
java·开发语言
光依旧1 小时前
MCP实战手记(九):生产化MCP Server的6层安全防护
java·人工智能·spring boot·安全·网络安全·ai agent·mcp
Vcaker1 小时前
Linux学习37-rook-ceph部署
linux·运维·学习
阳光九叶草LXGZXJ2 小时前
Linux-学习-12-JDK安装
java·linux·运维·学习
马剑威(威哥爱编程)2 小时前
【AI全栈后端12-04】Spring Boot 用结构化输出自动解析简历:让模型按你的 POJO 输出
java·人工智能·spring boot·后端
xcl09258 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构