当内存溢出频发,或垃圾回收成为并发瓶颈时,理解 JVM 的内存布局和 GC 行为,是性能调优的关键。代码演示在目录的HTML演示中
目录
[新生代(Young Generation)](#新生代(Young Generation))
[Eden 区](#Eden 区)
[Survivor 区](#Survivor 区)
[为什么需要 Survivor 区?](#为什么需要 Survivor 区?)
[老年代(Old Generation)](#老年代(Old Generation))
[GC 类型](#GC 类型)
从垃圾回收的角度:
Java 堆是垃圾收集器管理的主要区域,因此也被称作 GC 堆(Garbage Collected Heap)
所以 Java 堆还可以细分为:新生代和老年代;再细致一点有:Eden、Survivor、Old 等空间
在 JDK 7 版本及 JDK 7 版本之前,堆内存被通常分为下面三部分:
- 新生代内存(Young Generation)
- 老生代(Old Generation)
- 永久代(Permanent Generation)
下图所示的 Eden 区、两个 Survivor 区 S0 和 S1 都属于新生代,中间一层属于老年代,最下面一层属于永久代。

JDK 8 版本之后 PermGen(永久代/方法区) 已被 Metaspace(元空间) 取代,元空间使用的是本地内存。
新生代(Young Generation)
新生代分为三部分:
- Eden 区:新对象几乎都首先分配在这里。
- Survivor 区 :包含两个等大小的区域 S0 和 S1,通常比例为 Eden : S0 : S1 = 8 : 1 : 1 (可通过
-XX:SurvivorRatio
调整)。
Eden 区
- 新对象优先分配在 Eden。
- 大对象(如大数组)可能直接进入老年代,避免频繁复制。
- Eden 空间不足时,触发 Minor GC(也称 Young GC),回收不可达对象。
Survivor 区
- Minor GC 时,Eden 中存活的对象被复制到一个 Survivor 区(如 S0)。
- 下一次 Minor GC 时,存活对象从 Eden + S0 复制到 S1,S0 被清空。
- 两个 Survivor 区交替使用,始终有一个为空,这种机制称为 复制算法。
- 每次 Minor GC 后,存活对象的"年龄"加 1;达到阈值(默认 15,可通过
-XX:MaxTenuringThreshold
设置)后晋升到老年代。
为什么需要 Survivor 区?
若没有 Survivor 区,存活对象会直接进入老年代,导致:
- 老年代快速填满,频繁触发 Full GC;
- 无法区分短期与长期存活对象。
Survivor 区起到缓冲和筛选作用,只让真正长期存活的对象进入老年代,从而减少 Full GC 频率。
老年代(Old Generation)
老年代存放生命周期较长的对象,通常占堆内存的 2/3(默认新生代 : 老年代 = 1 : 2)。
以下对象会进入老年代:
- 长期存活对象:在新生代中经历多次 Minor GC 仍存活,且年龄达到阈值。
- 大对象:为避免复制开销,直接分配到老年代(部分 GC 支持)。
- Survivor 空间不足时的担保晋升:Minor GC 时若 Survivor 无法容纳所有存活对象,部分对象会提前晋升。
- 动态年龄判定:HotSpot 会判断,若某年龄以上对象总和超过 Survivor 一半,则直接晋升。
GC 类型
JVM 的垃圾回收按范围分为两类:
-
部分收集(Partial GC)
- Minor GC / Young GC:仅回收新生代。
- Major GC / Old GC:仅回收老年代(注意:某些语境中 "Major GC" 也指 Full GC)。
- Mixed GC:G1 GC 特有,回收新生代 + 部分老年代。
-
整堆收集(Full GC):回收整个 Java 堆和方法区,通常代价高、STW 时间长,应尽量避免。
HTML展示
新老年代转换演示

可直接复制代码丢到HTML中查看
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>JVM 垃圾回收机制演示</title>
<style>
body {
font-family: "Microsoft YaHei", "Segoe UI", sans-serif;
margin: 20px;
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
}
h1, h2 {
text-align: center;
color: #2c3e50;
}
.legend {
text-align: center;
margin: 15px 0;
font-weight: bold;
}
.legend span {
margin: 0 8px;
padding: 4px 8px;
border-radius: 4px;
color: white;
}
.eden-legend { background-color: #e74c3c; }
.s0-legend { background-color: #3498db; }
.s1-legend { background-color: #2ecc71; }
.old-legend { background-color: #9b59b6; }
.dead-legend { background-color: #95a5a6; }
.memory {
display: flex;
justify-content: center;
gap: 20px;
margin: 20px 0;
flex-wrap: wrap;
}
.region {
border: 2px solid #34495e;
padding: 12px;
width: 160px;
text-align: center;
background-color: white;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
}
.region h3 {
margin-top: 0;
font-size: 18px;
color: #2c3e50;
}
.object {
display: inline-block;
margin: 4px;
padding: 6px 10px;
border-radius: 5px;
color: white;
font-weight: bold;
font-size: 14px;
}
.eden .object { background-color: #e74c3c; }
.s0 .object { background-color: #3498db; }
.s1 .object { background-color: #2ecc71; }
.old .object { background-color: #9b59b6; }
.dead { opacity: 0.4; text-decoration: line-through; }
#nextBtn {
display: block;
margin: 20px auto;
padding: 12px 30px;
font-size: 18px;
background-color: #3498db;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
}
#nextBtn:hover { background-color: #2980b9; }
#nextBtn:disabled { background-color: #bdc3c7; cursor: not-allowed; }
.log {
background-color: #ecf0f1;
padding: 15px;
border-radius: 8px;
margin: 20px auto;
max-width: 800px;
font-family: monospace;
font-size: 16px;
text-align: center;
color: #2c3e50;
}
.explanation {
max-width: 900px;
margin: 30px auto;
padding: 20px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.explanation h3 {
color: #2980b9;
border-bottom: 1px solid #eee;
padding-bottom: 8px;
}
ul {
padding-left: 20px;
}
li {
margin-bottom: 8px;
}
</style>
</head>
<body>
<h1>🎯 JVM 垃圾回收机制演示:新生代与老年代</h1>
<div class="legend">
<span class="eden-legend">🔴 Eden</span>
<span class="s0-legend">🔵 S0</span>
<span class="s1-legend">🟢 S1</span>
<span class="old-legend">🟣 老年代</span>
<span class="dead-legend">💀 死亡对象</span>
</div>
<div class="memory">
<div class="region eden">
<h3>Eden</h3>
<div id="eden"></div>
</div>
<div class="region s0">
<h3>Survivor S0</h3>
<div id="s0"></div>
</div>
<div class="region s1">
<h3>Survivor S1</h3>
<div id="s1"></div>
</div>
<div class="region old">
<h3>老年代</h3>
<div id="old"></div>
</div>
</div>
<div class="log" id="log">准备开始... 点击"下一步"查看 JVM 内存变化</div>
<button id="nextBtn">下一步</button>
<div class="explanation">
<h3>📘 新生代(Young Generation)结构</h3>
<p>新生代通常被划分为三个部分:</p>
<ul>
<li><strong>Eden 区</strong>:新对象首先分配在此。</li>
<li><strong>Survivor 区</strong>:分为 S0 和 S1,比例通常为 Eden:S0:S1 = 8:1:1。</li>
</ul>
<h3>🔁 各区域作用</h3>
<ul>
<li><strong>Eden</strong>:对象创建地;满时触发 Minor GC。</li>
<li><strong>Survivor</strong>:Minor GC 时,存活对象在 S0/S1 之间"复制";每经历一次 GC,年龄 +1。</li>
<li><strong>老年代</strong>:存放长期存活对象(年龄 ≥ 阈值,默认 15)或大对象。</li>
</ul>
<h3>❓ 为什么需要 Survivor 区?</h3>
<ul>
<li>避免短期存活对象直接进入老年代,防止老年代快速填满。</li>
<li>通过"多次筛选",只让真正长期存活的对象晋升,减少 Full GC 频率。</li>
</ul>
<h3>⚙️ 晋升老年代的条件</h3>
<ul>
<li>对象年龄达到阈值(本演示设为 3)</li>
<li>Survivor 空间不足(分配担保)</li>
<li>动态年龄判定:某年龄以上对象总和 > Survivor 一半</li>
<li>大对象(如大数组)可能直接进入老年代</li>
</ul>
</div>
<script>
// 初始化状态
let eden = [];
let s0 = [];
let s1 = [];
let old = [];
let step = 0;
const AGE_THRESHOLD = 3;
function render() {
const regions = { eden, s0, s1, old };
for (const [name, list] of Object.entries(regions)) {
const el = document.getElementById(name);
if (el) {
el.innerHTML = list.map(obj =>
`<div class="object ${!obj.alive ? 'dead' : ''}" title="年龄: ${obj.age}">${obj.name}</div>`
).join('');
}
}
}
function log(msg) {
const logEl = document.getElementById('log');
if (logEl) logEl.innerText = msg;
}
function nextStep() {
step++;
try {
switch (step) {
case 1:
eden = [{name:'A',age:0,alive:true}, {name:'B',age:0,alive:true}, {name:'C',age:0,alive:true}];
log("✅ 创建 A、B、C → 放入 Eden(新对象首先进入 Eden)");
break;
case 2:
if (eden.length >= 2) {
eden[0].alive = false;
eden[1].alive = false;
}
log("⏳ A、B 无引用(死亡),C 仍被引用(存活)");
break;
case 3:
s0 = eden.filter(o => o.alive).map(o => ({...o, age: o.age + 1}));
eden = [];
log("♻️ Minor GC:回收 A、B;C(age=1) → S0;清空 Eden");
break;
case 4:
eden = [{name:'D',age:0,alive:true}, {name:'E',age:0,alive:true}, {name:'F',age:0,alive:true}];
log("✅ 创建 D、E、F → 放入 Eden");
break;
case 5:
if (eden.length >= 1) eden[0].alive = false;
log("⏳ D 死亡;E、F 存活;C(age=1) 在 S0 仍存活");
break;
case 6:
const toS1 = [...s0, ...eden.filter(o => o.alive)].map(o => ({...o, age: o.age + 1}));
s1 = toS1;
s0 = [];
eden = [];
log("♻️ Minor GC:C(age=2)、E、F → S1;清空 Eden 和 S0");
break;
case 7:
eden = [{name:'G',age:0,alive:true}, {name:'H',age:0,alive:true}];
log("✅ 创建 G、H → 放入 Eden");
break;
case 8:
if (eden.length >= 1) eden[0].alive = false;
log("⏳ G 死亡;H 存活;C(age=2)、E、F 在 S1 仍存活");
break;
case 9:
const candidates = [...s1, ...eden.filter(o => o.alive)].map(o => ({...o, age: o.age + 1}));
const promote = candidates.filter(o => o.age >= AGE_THRESHOLD);
const stay = candidates.filter(o => o.age < AGE_THRESHOLD);
old.push(...promote);
s0 = stay;
s1 = [];
eden = [];
const promotedNames = promote.map(o => o.name).join(', ');
const msg = promote.length > 0
? `♻️ Minor GC:H、E、F → S0;${promotedNames}(age=${AGE_THRESHOLD}) 晋升老年代!`
: "♻️ Minor GC:所有存活对象 → S0";
log(msg);
break;
case 10:
log("🎉 演示结束!C 已进入老年代");
document.getElementById('nextBtn').disabled = true;
return;
default:
if (step > 10) return;
}
render();
} catch (e) {
console.error("演示步骤出错:", e);
log("⚠️ 演示异常,请刷新页面重试。");
}
}
// 绑定按钮事件(避免内联 onclick)
document.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById('nextBtn');
if (btn) {
btn.addEventListener('click', nextStep);
}
render();
});
</script>
</body>
</html>
JVM垃圾回收算法演示
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
比如在新生代中,每次收集都会有大量对象死去,所以可以选择"复制"算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择"标记-清除"或"标记-整理"算法进行垃圾收集。

代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JVM垃圾回收算法详细动画演示</title>
<style>
body {
font-family: "Microsoft YaHei", sans-serif;
background-color: #eef2f3;
margin: 0;
padding: 20px;
color: #333;
}
h1 {
text-align: center;
color: #2c3e50;
}
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
gap: 20px;
}
.algorithm-section {
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 20px;
width: 45%;
min-width: 550px;
box-sizing: border-box;
}
.algorithm-title {
text-align: center;
margin-top: 0;
color: #2c3e50;
}
.animation-area {
width: 100%;
height: 200px;
border: 1px solid #ccc;
position: relative;
overflow: hidden;
margin-bottom: 15px;
background-color: #fafafa;
}
.memory-block {
position: absolute;
height: 30px;
top: 80px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
transition: all 0.5s ease;
}
.object-alive { background-color: #27ae60; } /* Green */
.object-dead { background-color: #95a5a6; } /* Gray */
.object-marked { background-color: #3498db; } /* Blue */
.object-moved { background-color: #8e44ad; } /* Purple */
.object-copied { background-color: #f39c12; } /* Orange */
.memory-region {
position: absolute;
height: 60px;
top: 70px;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: #2c3e50;
border: 1px dashed;
}
.region-from { border-color: #3498db; background-color: #ebf5fb; }
.region-to { border-color: #27ae60; background-color: #e8f8f5; }
.region-young { border-color: #3498db; background-color: #ebf5fb; }
.region-old { border-color: #8e44ad; background-color: #f4ecf7; }
.pointer {
position: absolute;
top: 40px;
height: 10px;
width: 2px;
background-color: #e74c3c;
transition: left 0.5s;
}
.phase-info {
text-align: center;
height: 40px;
font-weight: bold;
color: #2c3e50;
}
button {
display: block;
margin: 10px auto;
padding: 10px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
button:hover { background-color: #2980b9; }
button:disabled { background-color: #bdc3c7; cursor: not-allowed; }
.description {
font-size: 16px;
line-height: 1.5;
}
@media (max-width: 1200px) {
.algorithm-section { width: 90%; }
}
</style>
</head>
<body>
<h1>JVM垃圾回收算法动画演示</h1>
<div class="container">
<!-- 标记-清除算法 -->
<div class="algorithm-section">
<h2 class="algorithm-title">标记-清除算法 (Mark-and-Sweep)</h2>
<div class="phase-info" id="mark-sweep-phase">准备开始...</div>
<div class="animation-area" id="mark-sweep-animation"></div>
<button onclick="startMarkSweepDetailed()">开始演示</button>
<div class="description">
<p><strong>特点:</strong> 分为标记和清除两个阶段。标记所有存活对象,然后清除未标记的对象。</p>
<p><strong>局限性:</strong> 效率问题(标记和清除过程较慢);空间问题(产生内存碎片)。</p>
</div>
</div>
<!-- 复制算法 -->
<div class="algorithm-section">
<h2 class="algorithm-title">复制算法 (Copying)</h2>
<div class="phase-info" id="copying-phase">准备开始...</div>
<div class="animation-area" id="copying-animation"></div>
<button onclick="startCopyingDetailed()">开始演示</button>
<div class="description">
<p><strong>特点:</strong> 将内存分为两块,每次只使用一块。GC时将存活对象复制到另一块,清理已用空间。</p>
<p><strong>局限性:</strong> 可用内存减半;不适合老年代(存活对象多时复制开销大)。</p>
</div>
</div>
<!-- 标记-整理算法 -->
<div class="algorithm-section">
<h2 class="algorithm-title">标记-整理算法 (Mark-and-Compact)</h2>
<div class="phase-info" id="compact-phase">准备开始...</div>
<div class="animation-area" id="compact-animation"></div>
<button onclick="startCompactingDetailed()">开始演示</button>
<div class="description">
<p><strong>特点:</strong> 在标记后,将所有存活对象向一端移动,然后清理边界外的内存。</p>
<p><strong>局限性:</strong> 效率较低(多了整理步骤),适用于老年代这种GC频率低的场景。</p>
</div>
</div>
<!-- 分代收集算法 -->
<div class="algorithm-section">
<h2 class="algorithm-title">分代收集算法 (Generational Collection)</h2>
<div class="phase-info" id="generational-phase">准备开始...</div>
<div class="animation-area" id="generational-animation"></div>
<button onclick="startGenerationalDetailed()">开始演示</button>
<div class="description">
<p><strong>特点:</strong> 根据对象存活周期将堆分为新生代和老年代,分别采用合适的算法。</p>
<p><strong>原因:</strong> 新生代对象"朝生夕死",适合复制算法;老年代对象存活率高,适合标记-清除/整理。</p>
</div>
</div>
</div>
<script>
// --- Common Utilities ---
function createElement(tag, className, styles = {}) {
const el = document.createElement(tag);
if (className) el.className = className;
Object.assign(el.style, styles);
return el;
}
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
// --- Mark-and-Sweep Algorithm (Detailed) ---
async function startMarkSweepDetailed() {
const area = document.getElementById('mark-sweep-animation');
const info = document.getElementById('mark-sweep-phase');
const button = event.target;
button.disabled = true;
area.innerHTML = '';
const objects = [
{id: 'A', marked: false, alive: true},
{id: 'B', marked: false, alive: false},
{id: 'C', marked: false, alive: true},
{id: 'D', marked: false, alive: false},
{id: 'E', marked: false, alive: true},
{id: 'F', marked: false, alive: false}
];
const objectElements = [];
const totalWidth = area.clientWidth - 20;
const objectWidth = totalWidth / objects.length - 10;
objects.forEach((obj, i) => {
const el = createElement('div', `memory-block object-${obj.alive ? 'alive' : 'dead'}`, {
width: `${objectWidth}px`, left: `${i * (objectWidth + 10) + 10}px`
});
el.innerText = obj.id;
area.appendChild(el);
objectElements.push({data: obj, element: el});
});
info.innerText = "步骤 1: 对象创建完成,B, D, F 无引用变为垃圾。";
await sleep(1500);
info.innerText = "步骤 2: GC启动,进入标记阶段。";
await sleep(1000);
info.innerText = "步骤 3: 从GC Roots开始遍历,标记存活对象...";
await sleep(1000);
for (let item of objectElements) {
if (item.data.alive) {
item.data.marked = true;
item.element.className = 'memory-block object-marked';
await sleep(600);
}
}
info.innerText = "步骤 4: 标记阶段完成。";
await sleep(1000);
info.innerText = "步骤 5: 进入清除阶段,回收未标记对象...";
await sleep(1000);
for (let item of objectElements) {
if (!item.data.marked) {
item.element.style.opacity = '0.3';
item.element.style.transform = 'scale(0.8)';
await sleep(600);
}
}
info.innerText = "步骤 6: 清除完成,产生内存碎片。标记-清除算法演示结束。";
button.disabled = false;
}
// --- Copying Algorithm (Detailed) ---
async function startCopyingDetailed() {
const area = document.getElementById('copying-animation');
const info = document.getElementById('copying-phase');
const button = event.target;
button.disabled = true;
area.innerHTML = '';
const fromSpace = createElement('div', 'memory-region region-from', {
left: '10px', width: 'calc(50% - 20px)'
});
fromSpace.innerText = 'From Space';
const toSpace = createElement('div', 'memory-region region-to', {
right: '10px', width: 'calc(50% - 20px)'
});
toSpace.innerText = 'To Space';
area.appendChild(fromSpace);
area.appendChild(toSpace);
const objects = [
{id: 'X', alive: true}, {id: 'Y', alive: false},
{id: 'Z', alive: true}, {id: 'W', alive: true}
];
const objectElements = [];
const spaceWidth = (area.clientWidth / 2) - 30;
const objectWidth = spaceWidth / objects.length - 10;
objects.forEach((obj, i) => {
const el = createElement('div', `memory-block object-${obj.alive ? 'alive' : 'dead'}`, {
width: `${objectWidth}px`, left: `${i * (objectWidth + 10) + 20}px`, top: '85px'
});
el.innerText = obj.id;
fromSpace.appendChild(el);
objectElements.push({data: obj, element: el});
});
info.innerText = "步骤 1: Eden区 (From Space) 对象分配完成,Y死亡。";
await sleep(1500);
info.innerText = "步骤 2: Minor GC 触发,准备进行复制回收。";
await sleep(1000);
info.innerText = "步骤 3: 遍历From Space,识别存活对象...";
await sleep(1000);
info.innerText = "步骤 4: 将存活对象(X, Z, W)依次复制到To Space...";
await sleep(1000);
let toIndex = 0;
for (let item of objectElements) {
if (item.data.alive) {
const newEl = item.element.cloneNode(true);
newEl.className = 'memory-block object-copied';
newEl.style.left = `${toIndex * (objectWidth + 10) + 20}px`;
newEl.style.top = '85px';
toSpace.appendChild(newEl);
toIndex++;
await sleep(800);
}
}
info.innerText = "步骤 5: 复制完成,清空整个From Space...";
await sleep(1000);
fromSpace.innerHTML = 'From Space<br/>(已清空)';
fromSpace.style.backgroundColor = '#fdebd0';
info.innerText = "步骤 6: From和To角色互换。复制算法演示结束。";
button.disabled = false;
}
// --- Mark-and-Compact Algorithm (Detailed) ---
async function startCompactingDetailed() {
const area = document.getElementById('compact-animation');
const info = document.getElementById('compact-phase');
const button = event.target;
button.disabled = true;
area.innerHTML = '';
const objects = [
{id: 'M', marked: false, alive: true},
{id: 'N', marked: false, alive: false},
{id: 'O', marked: false, alive: true},
{id: 'P', marked: false, alive: false},
{id: 'Q', marked: false, alive: true},
{id: 'R', marked: false, alive: false}
];
const objectElements = [];
const totalWidth = area.clientWidth - 20;
const objectWidth = totalWidth / objects.length - 10;
objects.forEach((obj, i) => {
const el = createElement('div', `memory-block object-${obj.alive ? 'alive' : 'dead'}`, {
width: `${objectWidth}px`, left: `${i * (objectWidth + 10) + 10}px`
});
el.innerText = obj.id;
area.appendChild(el);
objectElements.push({data: obj, element: el});
});
info.innerText = "步骤 1: 老年代内存状态,N, P, R 为垃圾对象。";
await sleep(1500);
info.innerText = "步骤 2: Full GC 启动,进入标记阶段。";
await sleep(1000);
info.innerText = "步骤 3: 标记所有存活对象...";
await sleep(1000);
for (let item of objectElements) {
if (item.data.alive) {
item.data.marked = true;
item.element.className = 'memory-block object-marked';
await sleep(600);
}
}
info.innerText = "步骤 4: 标记完成。";
await sleep(1000);
info.innerText = "步骤 5: 进入整理阶段,将存活对象向内存一端移动...";
await sleep(1000);
let compactIndex = 0;
for (let item of objectElements) {
if (item.data.marked) {
item.element.className = 'memory-block object-moved';
const targetLeft = compactIndex * (objectWidth + 10) + 10;
const currentLeft = parseInt(item.element.style.left);
const delta = targetLeft - currentLeft;
item.element.style.transform = `translateX(${delta}px)`;
compactIndex++;
await sleep(700);
}
}
info.innerText = "步骤 6: 整理完成,清理边界外的内存...";
await sleep(1000);
for (let item of objectElements) {
if (!item.data.marked) {
item.element.style.opacity = '0.3';
item.element.style.transform += ' scale(0.8)';
await sleep(600);
}
}
info.innerText = "步骤 7: 内存整理完毕,无碎片。演示结束。";
button.disabled = false;
}
// --- Generational Collection Algorithm (Detailed) ---
async function startGenerationalDetailed() {
const area = document.getElementById('generational-animation');
const info = document.getElementById('generational-phase');
const button = event.target;
button.disabled = true;
area.innerHTML = '';
const youngGen = createElement('div', 'memory-region region-young', {
top: '10px', left: '10px', width: 'calc(100% - 20px)'
});
youngGen.innerText = '新生代 (Young Generation)';
const oldGen = createElement('div', 'memory-region region-old', {
bottom: '10px', left: '10px', width: 'calc(100% - 20px)'
});
oldGen.innerText = '老年代 (Old Generation)';
area.appendChild(youngGen);
area.appendChild(oldGen);
info.innerText = "步骤 1: JVM内存分为新生代和老年代。";
await sleep(1500);
info.innerText = "步骤 2: 新生代对象'朝生夕死',采用复制算法。";
await sleep(1000);
youngGen.style.boxShadow = 'inset 0 0 10px #3498db';
await sleep(1000);
youngGen.style.boxShadow = 'none';
await sleep(500);
info.innerText = "步骤 3: 老年代对象存活率高,采用标记-清除/整理。";
await sleep(1000);
oldGen.style.boxShadow = 'inset 0 0 10px #8e44ad';
await sleep(1000);
oldGen.style.boxShadow = 'none';
await sleep(500);
info.innerText = "步骤 4: 对象在新生代经历多次GC后晋升到老年代。";
await sleep(1000);
const obj = createElement('div', 'memory-block object-alive', {
width: '30px', height: '20px', top: '25px', left: '45%', fontSize: '12px'
});
obj.innerText = 'Obj';
youngGen.appendChild(obj);
await sleep(1000);
obj.style.transition = 'all 1s ease';
obj.style.top = '155px';
obj.style.backgroundColor = '#8e44ad';
await sleep(1200);
info.innerText = "步骤 5: 不同代使用最适合的算法,这就是分代收集。";
await sleep(1500);
info.innerText = "分代收集算法演示完成。";
button.disabled = false;
}
</script>
</body>
</html>