企鹅不让说实话 發表於 2026-1-8 18:25:00

JVM 堆内存分代

<p><span data-cke-copybin-start="1">​</span>今天我们一起来聊一聊 <strong>JVM 堆内存</strong>。</p>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202601/1171560-20260108182258403-1042762825.png" alt="Java Heap1"></p>
<p><strong>Java Heap</strong>(堆内存)由 <strong>Young Generation</strong>(新生代,约占 <strong>1/3&nbsp;</strong>)和&nbsp;<strong>Old Generation</strong>(老年代,约占 <strong>2/3</strong> )组成。</p>
<p><strong>Young Generation </strong>又由&nbsp;<strong>Eden Space</strong>(伊甸园区,占新生代 <strong>80%&nbsp;</strong>)、<strong>Survivor Space 0</strong>(幸存者区0,占新生代 <strong>10%&nbsp;</strong>)和 <strong>Survivor Space 1</strong>(幸存者区1,占新生代 <strong>10%&nbsp;</strong>)组成。</p>
<p><strong>对象的生命周期</strong>:</p>
<p><img src="https://img2024.cnblogs.com/blog/1171560/202601/1171560-20260108182353974-1428015339.png" alt="对象生命周期"></p>
<p><strong>Young Generation</strong>(新生代):</p>
<ul>
<li>存储 <strong>新创建</strong>、<strong>存活周期极短</strong> 的对象,比如方法内的局部变量、临时对象。默认占堆总容量 <strong>1/3 </strong>。</li>
<li>触发 <strong>Minor GC</strong>(新生代 GC),频率极高(毫秒 / 秒级),但耗时极短(几十毫秒)。</li>
<li>Eden 区是 Minor GC 的 "触发源头",调大 Eden 区可减少 Minor GC 次数。</li>
</ul>
<p><strong>Eden Space</strong>(伊甸园区):新对象的 "默认出生地",<strong>99% 的新对象&nbsp;</strong>都会优先分配到 Eden 区(除非是超大对象直接进入老年代)。占新生代 <strong>80%&nbsp;</strong>。</p>
<p><strong>Survivor Space 0/1</strong>(幸存者区 0/1,简称 S0/S1,也叫 From 区 / To 区):</p>
<ul>
<li>新生代 GC 后存活对象的 <strong>"临时中转站"</strong>,避免存活对象直接进入老年代。<strong>两个区会动态互换角色</strong>。各占新生代 <strong>10%</strong>,合计 20%。</li>
<li>S0 和 S1&nbsp;<strong>永远有一个是空的</strong>(这是 JVM 的设计巧思)。</li>
<li>每经历一次 Minor GC,存活对象的 <strong>"年龄 + 1"</strong>。</li>
</ul>
<p><strong>S0/S1 的交互</strong> 示例:</p>
<ul>
<li>① 初始状态:Eden 有对象,S0 有对象,S1 为空;</li>
<li>② Eden 触发 Minor GC → 回收 Eden+S0 的垃圾对象,存活对象复制到 S1,清空 Eden+S0;</li>
<li>③ 此时 S1 非空、S0 为空,两者角色互换(S0=To 区,S1=From 区);</li>
<li>④ 下次 Minor GC 重复上述过程,存活对象在 S0/S1 之间 <strong>"来回复制"</strong>。</li>
</ul>
<p><strong>Old Generation</strong>(老年代):</p>
<ul>
<li>存储&nbsp;<strong>长期存活、体积较大&nbsp;</strong>的对象,比如单例对象、缓存对象、经历多次 Minor GC 仍存活的对象。默认占堆总容量 <strong>2/3</strong>。</li>
<li>触发&nbsp;<strong>Major GC / Full GC</strong>,频率极低,但耗时极长。</li>
<li>老年代大小决定 Full GC 频率 —— 老年代越大,Full GC 频率越低,但单次 Full GC 耗时越长。</li>
</ul>
<p><strong>对象进入老年代的条件</strong>:</p>
<ul>
<li><strong>年龄达标</strong>:对象在 S0/S1 之间复制次数达到阈值(默认 15 次,<code>-XX:MaxTenuringThreshold</code>调整);</li>
<li><strong>大对象</strong>:超过阈值的对象(<code>-XX:PretenureSizeThreshold</code>)直接进入老年代;</li>
<li><strong>空间担保失败</strong>:Minor GC 后 Survivor 区放不下存活对象,多余对象直接晋升老年代;</li>
<li><strong>动态年龄判断</strong>:Survivor 区中相同年龄对象总和超过 50%,该年龄及以上对象直接进入老年代。</li>
</ul>
<p>不同存活周期的对象放在不同区域,用不同算法回收,保证 <strong>GC</strong> 效率,这就是&nbsp;<strong>"分代回收" </strong>的核心思想。</p>
<p style="text-align: right"><span style="color: rgba(53, 152, 219, 1)">努力的意义,不在于追逐别人的高度,而是拼尽全力,为自己创造一个绝地反击的故事。-- 烟沙九洲</span></p><br><br>
来源:https://www.cnblogs.com/yanshajiuzhou/p/19458321
頁: [1]
查看完整版本: JVM 堆内存分代