Xiaomi Mimo UltraSpeed初体验
上次参与了Xiaomi 100T Token的活动,最后得了820亿Token,花了20亿。不得不说白嫖的确实香。
最近Xiaomi又给我发邮件, v2.5-UltraSpeed内测延期,我也是赶快申请,刚刚通过审核。
用的网页版,先问了Go中GC流程,用了text展示流程

点击查看代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Go GC 三色标记流程图解</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link
href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;600;700&family=Noto+Sans+SC:wght@300;400;500;700;900&display=swap"
rel="stylesheet">
<style>
:root {
--bg: #0a0e17;
--surface: #111827;
--surface2: #1a2235;
--border: #1e2d45;
--accent: #22d3ee;
--accent2: #f59e0b;
--accent3: #10b981;
--red: #ef4444;
--white-obj: #e2e8f0;
--grey-obj: #94a3b8;
--black-obj: #1e293b;
--text: #e2e8f0;
--text-muted: #64748b;
--stw-red: rgba(239, 68, 68, 0.12);
--stw-border: rgba(239, 68, 68, 0.4);
--mark-blue: rgba(34, 211, 238, 0.08);
--mark-border: rgba(34, 211, 238, 0.3);
--sweep-green: rgba(16, 185, 129, 0.08);
--sweep-border: rgba(16, 185, 129, 0.3);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: var(--bg);
color: var(--text);
font-family: 'Noto Sans SC', sans-serif;
line-height: 1.7;
overflow-x: hidden;
}
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 15% 20%, rgba(34, 211, 238, 0.04) 0%, transparent 50%),
radial-gradient(ellipse at 85% 80%, rgba(245, 158, 11, 0.03) 0%, transparent 50%),
radial-gradient(ellipse at 50% 50%, rgba(16, 185, 129, 0.02) 0%, transparent 70%);
pointer-events: none;
z-index: 0;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
position: relative;
z-index: 1;
}
/* Header */
header {
padding: 80px 0 40px;
text-align: center;
}
header .badge {
display: inline-block;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
letter-spacing: 3px;
text-transform: uppercase;
color: var(--accent);
border: 1px solid rgba(34, 211, 238, 0.3);
padding: 6px 20px;
border-radius: 100px;
margin-bottom: 28px;
background: rgba(34, 211, 238, 0.05);
}
h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
font-weight: 900;
letter-spacing: -1px;
margin-bottom: 16px;
background: linear-gradient(135deg, #e2e8f0, #94a3b8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
header p {
color: var(--text-muted);
font-size: 1.05rem;
max-width: 640px;
margin: 0 auto;
}
/* Color Legend */
.legend-bar {
display: flex;
justify-content: center;
gap: 32px;
margin: 48px 0 60px;
flex-wrap: wrap;
}
.legend-item {
display: flex;
align-items: center;
gap: 10px;
font-size: 0.95rem;
color: var(--text-muted);
}
.legend-dot {
width: 28px;
height: 28px;
border-radius: 50%;
border: 3px solid;
flex-shrink: 0;
}
.legend-dot.white {
background: #e2e8f0;
border-color: #94a3b8;
}
.legend-dot.grey {
background: #94a3b8;
border-color: #64748b;
}
.legend-dot.black {
background: #1e293b;
border-color: #22d3ee;
}
/* Timeline */
.timeline {
position: relative;
margin-bottom: 80px;
}
.timeline-line {
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: 3px;
background: linear-gradient(to bottom, var(--border), var(--accent), var(--border));
transform: translateX(-50%);
border-radius: 2px;
}
.phase {
position: relative;
margin-bottom: 80px;
opacity: 0;
transform: translateY(30px);
animation: fadeInUp 0.6s ease forwards;
}
.phase:nth-child(2) {
animation-delay: 0.1s;
}
.phase:nth-child(3) {
animation-delay: 0.2s;
}
.phase:nth-child(4) {
animation-delay: 0.3s;
}
.phase:nth-child(5) {
animation-delay: 0.4s;
}
.phase:nth-child(6) {
animation-delay: 0.5s;
}
@keyframes fadeInUp {
to {
opacity: 1;
transform: translateY(0);
}
}
.phase-marker {
position: absolute;
left: 50%;
top: 24px;
transform: translateX(-50%);
z-index: 3;
}
.marker-dot {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 16px;
border: 3px solid;
background: var(--bg);
}
.marker-dot.stw {
border-color: var(--red);
color: var(--red);
box-shadow: 0 0 20px rgba(239, 68, 68, 0.3);
}
.marker-dot.concurrent {
border-color: var(--accent);
color: var(--accent);
box-shadow: 0 0 20px rgba(34, 211, 238, 0.2);
}
.marker-dot.sweep {
border-color: var(--accent3);
color: var(--accent3);
box-shadow: 0 0 20px rgba(16, 185, 129, 0.2);
}
.phase-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 60px;
align-items: start;
}
.phase.left .text-panel {
grid-column: 1;
text-align: right;
padding-right: 20px;
}
.phase.left .viz-panel {
grid-column: 2;
padding-left: 20px;
}
.phase.right .text-panel {
grid-column: 2;
text-align: left;
padding-left: 20px;
}
.phase.right .viz-panel {
grid-column: 1;
text-align: right;
padding-right: 20px;
}
.phase-tag {
display: inline-block;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
letter-spacing: 2px;
text-transform: uppercase;
padding: 4px 14px;
border-radius: 4px;
margin-bottom: 12px;
}
.phase-tag.stw {
background: var(--stw-red);
color: var(--red);
border: 1px solid var(--stw-border);
}
.phase-tag.concurrent {
background: var(--mark-blue);
color: var(--accent);
border: 1px solid var(--mark-border);
}
.phase-tag.sweep-tag {
background: var(--sweep-green);
color: var(--accent3);
border: 1px solid var(--sweep-border);
}
.phase-title {
font-size: 1.6rem;
font-weight: 700;
margin-bottom: 12px;
letter-spacing: -0.5px;
}
.phase-desc {
color: var(--text-muted);
font-size: 0.95rem;
line-height: 1.8;
}
.phase-desc strong {
color: var(--text);
}
/* Visualization panels */
.viz-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 28px;
position: relative;
overflow: hidden;
}
.viz-card::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(34, 211, 238, 0.03), transparent);
pointer-events: none;
}
.viz-card.stw-card {
border-color: var(--stw-border);
}
.viz-card.concurrent-card {
border-color: var(--mark-border);
}
.viz-card.sweep-card {
border-color: var(--sweep-border);
}
/* Object Graph */
.obj-graph {
display: flex;
flex-direction: column;
gap: 24px;
position: relative;
}
.graph-row {
display: flex;
align-items: center;
gap: 12px;
justify-content: center;
flex-wrap: wrap;
}
.obj-node {
width: 56px;
height: 56px;
border-radius: 14px;
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 15px;
position: relative;
transition: all 0.4s ease;
border: 3px solid;
flex-shrink: 0;
}
.obj-node.white-node {
background: #334155;
border-color: #475569;
color: #94a3b8;
}
.obj-node.grey-node {
background: #475569;
border-color: var(--accent2);
color: #fbbf24;
box-shadow: 0 0 16px rgba(245, 158, 11, 0.25);
animation: pulseGrey 2s ease-in-out infinite;
}
@keyframes pulseGrey {
0%,
100% {
box-shadow: 0 0 16px rgba(245, 158, 11, 0.25);
}
50% {
box-shadow: 0 0 24px rgba(245, 158, 11, 0.4);
}
}
.obj-node.black-node {
background: var(--bg);
border-color: var(--accent);
color: var(--accent);
box-shadow: 0 0 16px rgba(34, 211, 238, 0.2);
}
.obj-node.root-node {
width: 64px;
height: 64px;
border-radius: 50%;
background: linear-gradient(135deg, #1e1b4b, #312e81);
border-color: #818cf8;
color: #a5b4fc;
font-size: 13px;
}
.obj-node.dead-node {
background: rgba(239, 68, 68, 0.1);
border-color: rgba(239, 68, 68, 0.4);
color: var(--red);
opacity: 0.5;
text-decoration: line-through;
}
.arrow {
font-family: 'JetBrains Mono', monospace;
color: var(--text-muted);
font-size: 18px;
line-height: 1;
}
.arrow.highlight {
color: var(--accent2);
}
.label-sm {
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--text-muted);
text-align: center;
margin-top: 6px;
}
/* Timeline bar */
.timeline-bar {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin-bottom: 60px;
}
.bar-track {
display: flex;
height: 52px;
border-radius: 8px;
overflow: hidden;
position: relative;
}
.bar-seg {
display: flex;
align-items: center;
justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-weight: 600;
letter-spacing: 1px;
text-transform: uppercase;
position: relative;
transition: all 0.3s ease;
}
.bar-seg:hover {
filter: brightness(1.3);
}
.bar-seg.stw-seg {
background: rgba(239, 68, 68, 0.2);
color: var(--red);
border: 1px solid rgba(239, 68, 68, 0.3);
flex: 0 0 40px;
}
.bar-seg.mark-seg {
background: rgba(34, 211, 238, 0.12);
color: var(--accent);
border: 1px solid rgba(34, 211, 238, 0.2);
flex: 5;
}
.bar-seg.sweep-seg {
background: rgba(16, 185, 129, 0.1);
color: var(--accent3);
border: 1px solid rgba(16, 185, 129, 0.2);
flex: 3;
}
.bar-labels {
display: flex;
margin-top: 8px;
font-family: 'JetBrains Mono', monospace;
font-size: 10px;
color: var(--text-muted);
}
.bar-labels span:first-child {
flex: 0 0 40px;
text-align: center;
}
.bar-labels span:nth-child(2) {
flex: 5;
text-align: center;
}
.bar-labels span:nth-child(3) {
flex: 0 0 40px;
text-align: center;
}
.bar-labels span:nth-child(4) {
flex: 3;
text-align: center;
}
/* Write barrier animation */
.write-demo {
display: flex;
align-items: center;
gap: 8px;
margin-top: 16px;
padding: 12px 16px;
background: rgba(245, 158, 11, 0.06);
border: 1px solid rgba(245, 158, 11, 0.2);
border-radius: 8px;
font-family: 'JetBrains Mono', monospace;
font-size: 12px;
color: var(--accent2);
line-height: 1.6;
}
/* Code block */
.code-block {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 10px;
padding: 20px;
margin-top: 16px;
font-family: 'JetBrains Mono', monospace;
font-size: 12.5px;
line-height: 1.8;
overflow-x: auto;
color: #94a3b8;
}
.code-block .kw {
color: #c084fc;
}
.code-block .fn {
color: #22d3ee;
}
.code-block .str {
color: #34d399;
}
.code-block .cm {
color: #475569;
}
.code-block .op {
color: #f59e0b;
}
/* Step indicator */
.step-pills {
display: flex;
gap: 8px;
margin-top: 12px;
flex-wrap: wrap;
}
.pill {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
padding: 4px 12px;
border-radius: 100px;
background: var(--surface2);
color: var(--text-muted);
border: 1px solid var(--border);
}
.pill.active {
background: rgba(34, 211, 238, 0.1);
border-color: rgba(34, 211, 238, 0.3);
color: var(--accent);
}
/* Summary Section */
.summary {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 20px;
padding: 48px;
margin: 40px 0 100px;
position: relative;
overflow: hidden;
}
.summary::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(34, 211, 238, 0.03), transparent 50%, rgba(245, 158, 11, 0.02));
pointer-events: none;
}
.summary h2 {
font-size: 1.8rem;
font-weight: 700;
margin-bottom: 28px;
}
.summary-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
.summary-card {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
text-align: center;
}
.summary-card .num {
font-family: 'JetBrains Mono', monospace;
font-size: 2rem;
font-weight: 700;
margin-bottom: 6px;
}
.summary-card .num.red {
color: var(--red);
}
.summary-card .num.cyan {
color: var(--accent);
}
.summary-card .num.green {
color: var(--accent3);
}
.summary-card .num.yellow {
color: var(--accent2);
}
.summary-card .desc {
font-size: 0.85rem;
color: var(--text-muted);
}
/* Responsive */
@media (max-width: 768px) {
.phase-content {
grid-template-columns: 1fr;
gap: 20px;
}
.phase.left .text-panel,
.phase.right .text-panel,
.phase.left .viz-panel,
.phase.right .viz-panel {
grid-column: 1;
text-align: left;
padding: 0;
}
.timeline-line {
display: none;
}
.phase-marker {
display: none;
}
.obj-node {
width: 44px;
height: 44px;
font-size: 12px;
}
.obj-node.root-node {
width: 50px;
height: 50px;
}
header {
padding: 40px 0 20px;
}
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="badge">Go Runtime — Garbage Collector</div>
<h1>三色标记 GC 全流程图解</h1>
<p>从标记准备到并发清扫,完整理解 Go 垃圾回收器的工作原理与 STW 暂停的必要性</p>
</div>
</header>
<div class="container">
<!-- Color Legend -->
<div class="legend-bar">
<div class="legend-item">
<div class="legend-dot white"></div>
<span>白色 = 未扫描 / 待回收</span>
</div>
<div class="legend-item">
<div class="legend-dot grey"></div>
<span>灰色 = 已发现 / 子节点待扫描</span>
</div>
<div class="legend-item">
<div class="legend-dot black"></div>
<span>黑色 = 完全扫描 / 确认存活</span>
</div>
</div>
<!-- Overview Timeline Bar -->
<div class="timeline-bar">
<div class="bar-track">
<div class="bar-seg stw-seg">STW</div>
<div class="bar-seg mark-seg">并发标记 Concurrent Mark</div>
<div class="bar-seg stw-seg">STW</div>
<div class="bar-seg sweep-seg">并发清扫 Concurrent Sweep</div>
</div>
<div class="bar-labels">
<span>标记准备</span>
<span>GC Worker 遍历对象图(应用正常运行)</span>
<span>标记终止</span>
<span>回收白色对象</span>
</div>
</div>
<!-- ===== Phase 0: Initial State ===== -->
<div class="timeline">
<div class="timeline-line"></div>
<!-- Phase: Initial State -->
<div class="phase left" style="animation-delay:0s">
<div class="phase-marker">
<div class="marker-dot concurrent" style="border-color:#475569;color:#475569">0</div>
</div>
<div class="text-panel">
<div class="phase-tag concurrent"
style="background:rgba(71,85,105,0.15);border-color:rgba(71,85,105,0.4);color:#94a3b8">初始状态
</div>
<div class="phase-title">内存中的一堆对象</div>
<div class="phase-desc">
堆上有 A~H 共 8 个对象,它们之间有引用关系。<br>
其中 <strong style="color:#ef4444">G 和 H 没有被任何人引用</strong>——它们是垃圾,但程序还不知道。<br><br>
GC 的任务:找出所有从根可达的对象,剩下的就是垃圾。
</div>
</div>
<div class="viz-panel">
<div class="viz-card">
<div class="obj-graph">
<div class="graph-row">
<div>
<div class="obj-node root-node">栈</div>
<div class="label-sm">goroutine 栈</div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node white-node">A</div>
<div class="label-sm">根对象</div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node white-node">C</div>
<div class="label-sm"></div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node white-node">E</div>
<div class="label-sm"></div>
</div>
</div>
<div class="graph-row" style="padding-left:120px">
<span class="arrow">↙</span>
<div>
<div class="obj-node white-node">B</div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node white-node">D</div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node white-node">F</div>
</div>
</div>
<div class="graph-row" style="padding-left:200px;margin-top:8px">
<div>
<div class="obj-node dead-node">G</div>
<div class="label-sm" style="color:var(--red)">无引用</div>
</div>
<span class="arrow" style="margin:0 12px"> </span>
<div>
<div class="obj-node dead-node">H</div>
<div class="label-sm" style="color:var(--red)">无引用</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Phase 1: STW Mark Setup -->
<div class="phase right">
<div class="phase-marker">
<div class="marker-dot stw">1</div>
</div>
<div class="text-panel">
<div class="phase-tag stw">STW — 约 0.1ms</div>
<div class="phase-title">标记准备 Mark Setup</div>
<div class="phase-desc">
<strong>第一次短暂暂停应用。</strong><br><br>
做两件事:<br>
<strong style="color:#ef4444">① 开启写屏障</strong> (Write Barrier)<br>
在每个指针写入操作前插入监控代码。这样并发标记期间如果应用修改了引用关系,GC 不会遗漏。<br><br>
<strong style="color:#ef4444">② 扫描所有 goroutine 栈</strong><br>
找到栈上的指针,作为 GC 遍历的"入口",全部标为灰色放入工作队列。
</div>
<div class="code-block">
<span class="cm">// 写屏障:每次写指针前自动执行</span><br>
<span class="kw">func</span> <span class="fn">writeBarrier</span>(slot, ptr *Object) {<br>
<span class="fn">shade</span>(ptr) <span class="cm">//
把目标标灰,保证不丢</span><br>
*slot = ptr <span class="cm">// 正常写入</span><br>
}
</div>
</div>
<div class="viz-panel">
<div class="viz-card stw-card">
<div style="text-align:center;margin-bottom:16px">
<span
style="font-family:'JetBrains Mono';font-size:11px;color:var(--red);letter-spacing:2px">APPLICATION
PAUSED</span>
</div>
<div class="obj-graph">
<div class="graph-row">
<div>
<div class="obj-node root-node" style="opacity:0.5">栈</div>
<div class="label-sm">暂停中...</div>
</div>
<span class="arrow">→</span>
<div>
<div class="obj-node grey-node">A</div>
<div class="label-sm">标灰 → 入队</div>
</div>
</div>
<div class="graph-row" style="padding-left:60px">
<span class="arrow">↙</span>
<div>
<div class="obj-node grey-node">B</div>
<div class="label-sm">标灰 → 入队</div>
</div>
</div>
<div style="text-align:center;margin-top:8px">
<div class="graph-row" style="justify-content:center">
<div>
<div class="obj-node white-node">C</div>
</div>
<span class="arrow" style="margin:0 8px"> </span>
<div>
<div class="obj-node white-node">D</div>
</div>
<span class="arrow" style="margin:0 8px"> </span>
<div>
<div class="obj-node white-node">E</div>
</div>
<span class="arrow" style="margin:0 8px"> </span>
<div>
<div class="obj-node white-node">F</div>
</div>
</div>
<div class="label-sm">仍为白色(未处理)</div>
</div>
<div class="graph-row" style="justify-content:center;margin-top:8px">
<div>
<div class="obj-node dead-node">G</div>
</div>
<span class="arrow" style="margin:0 12px"> </span>
<div>
<div class="obj-node dead-node">H</div>
</div>
</div>
</div>
<div class="step-pills" style="justify-content:center;margin-top:16px">
<div class="pill active">写屏障 ON</div>
<div class="pill active">栈根扫描</div>
</div>
</div>
</div>
</div>
<!-- Phase 2: Concurrent Marking -->
<div class="phase left">
<div class="phase-marker">
<div class="marker-dot concurrent">2</div>
</div>
<div class="text-panel">
<div class="phase-tag concurrent">并发 — 时间最长的阶段</div>
<div class="phase-title">并发标记 Concurrent Mark</div>
<div class="phase-desc">
<strong>应用恢复运行!</strong> GC Worker goroutine 与应用并发执行。<br><br>
核心逻辑:<strong style="color:var(--accent2)">不断从灰色队列取对象,扫描其子指针</strong><br><br>
<strong>每一步:</strong><br>
1. 取出一个灰色对象<br>
2. 遍历它的所有指针字段<br>
3. 子对象若为白色 → 标灰并入队<br>
4. 自己标黑(扫描完毕)<br>
5. 重复直到队列为空<br><br>
此时如果应用执行了 <code style="color:var(--accent2)">objA.ptr = objX</code>,<br>
写屏障会把 X 标灰,防止误回收。
</div>
<div class="write-demo">
<span style="font-size:16px">⚡</span>
<span>应用写入 <span style="color:#f0abfc">A.ptr = X</span> → 写屏障拦截 → <span
style="color:var(--accent2)">X 标灰入队</span></span>
</div>
</div>
<div class="viz-panel">
<div class="viz-card concurrent-card">
<div style="text-align:center;margin-bottom:16px">
<span
style="font-family:'JetBrains Mono';font-size:11px;color:var(--accent);letter-spacing:2px">APPLICATION
RUNNING + GC WORKERS</span>
</div>
<div class="obj-graph" id="markSteps">
<!-- Step by step marking -->
<div>
<div
style="font-family:'JetBrains Mono';font-size:11px;color:var(--text-muted);margin-bottom:8px">
Round 1: A → 查子指针 → 发现 C</div>
<div class="graph-row">
<div>
<div class="obj-node black-node">A</div>
<div class="label-sm">黑</div>
</div>
<span class="arrow highlight">→</span>
<div>
<div class="obj-node grey-node">C</div>
<div class="label-sm">新灰</div>
</div>
<span class="arrow" style="margin:0 6px"> </span>
<div>
<div class="obj-node grey-node">B</div>
<div class="label-sm">仍在队列</div>
</div>
</div>
</div>
<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">
<div>
<div
style="font-family:'JetBrains Mono';font-size:11px;color:var(--text-muted);margin-bottom:8px">
Round 2: B → 查子指针 → 发现 D</div>
<div class="graph-row">
<div>
<div class="obj-node black-node">A</div>
<div class="label-sm">黑</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">B</div>
<div class="label-sm">新黑</div>
</div>
<span class="arrow highlight">→</span>
<div>
<div class="obj-node grey-node">D</div>
<div class="label-sm">新灰</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node grey-node">C</div>
<div class="label-sm">仍在队列</div>
</div>
</div>
</div>
<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">
<div>
<div
style="font-family:'JetBrains Mono';font-size:11px;color:var(--text-muted);margin-bottom:8px">
Round 3: C → 发现 E | Round 4: D → 发现 F</div>
<div class="graph-row">
<div>
<div class="obj-node black-node">A</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">B</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">C</div>
</div>
<span class="arrow highlight">→</span>
<div>
<div class="obj-node grey-node">E</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">D</div>
</div>
<span class="arrow highlight">→</span>
<div>
<div class="obj-node grey-node">F</div>
</div>
</div>
</div>
<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">
<div>
<div
style="font-family:'JetBrains Mono';font-size:11px;color:var(--text-muted);margin-bottom:8px">
Round 5: E, F → 无子指针 → 全部变黑</div>
<div class="graph-row">
<div>
<div class="obj-node black-node">A</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">B</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">C</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">D</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">E</div>
</div>
<span class="arrow" style="margin:0 4px"> </span>
<div>
<div class="obj-node black-node">F</div>
</div>
</div>
<div class="label-sm" style="margin-top:8px;color:var(--accent)">队列空了 — 标记完成!
</div>
</div>
<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">
<div style="text-align:center">
<div class="graph-row" style="justify-content:center">
<div>
<div class="obj-node dead-node">G</div>
</div>
<span class="arrow" style="margin:0 16px"> </span>
<div>
<div class="obj-node dead-node">H</div>
</div>
</div>
<div class="label-sm" style="color:var(--red)">标记结束后仍为白色 = 垃圾!</div>
</div>
</div>
</div>
</div>
</div>
<!-- Phase 3: STW Mark Termination -->
<div class="phase right">
<div class="phase-marker">
<div class="marker-dot stw">3</div>
</div>
<div class="text-panel">
<div class="phase-tag stw">STW — 约 0.1ms</div>
<div class="phase-title">标记终止 Mark Termination</div>
<div class="phase-desc">
<strong>第二次短暂暂停应用。</strong><br><br>
这次做收尾工作:<br><br>
<strong style="color:#ef4444">① 排空工作队列</strong><br>
确保最后几个灰色对象也变黑,没有遗漏。<br><br>
<strong style="color:#ef4444">② 关闭写屏障</strong><br>
标记已经结束,不再需要监控指针变化了。关了写屏障,应用能跑得更快。<br><br>
<strong style="color:#ef4444">③ 重置 GC 状态</strong><br>
清除标记位,计算下一轮 GC 触发阈值(pacer)。<br><br>
<span style="color:var(--text-muted)">为什么必须暂停?<br>关写屏障 + 清状态必须原子完成,不能一边关一边应用还在用。</span>
</div>
</div>
<div class="viz-panel">
<div class="viz-card stw-card">
<div style="text-align:center;margin-bottom:16px">
<span
style="font-family:'JetBrains Mono';font-size:11px;color:var(--red);letter-spacing:2px">APPLICATION
PAUSED — FINAL CLEANUP</span>
</div>
<div class="obj-graph">
<div style="display:flex;flex-direction:column;gap:20px">
<!-- Checklist -->
<div
style="display:flex;align-items:center;gap:12px;padding:14px 18px;background:rgba(239,68,68,0.06);border:1px solid rgba(239,68,68,0.15);border-radius:10px">
<span style="font-size:18px">✅</span>
<span style="font-size:14px">排空工作队列(最后灰色 → 黑色)</span>
</div>
<div
style="display:flex;align-items:center;gap:12px;padding:14px 18px;background:rgba(239,68,68,0.06);border:1px solid rgba(239,68,68,0.15);border-radius:10px">
<span style="font-size:18px">✅</span>
<span style="font-size:14px">关闭写屏障 Write Barrier OFF</span>
</div>
<div
style="display:flex;align-items:center;gap:12px;padding:14px 18px;background:rgba(239,68,68,0.06);border:1px solid rgba(239,68,68,0.15);border-radius:10px">
<span style="font-size:18px">✅</span>
<span style="font-size:14px">重置标记位,计算下轮 GC 阈值</span>
</div>
</div>
<div style="margin-top:24px">
<div class="graph-row" style="justify-content:center">
<div>
<div class="obj-node black-node">A</div>
</div>
<div>
<div class="obj-node black-node">B</div>
</div>
<div>
<div class="obj-node black-node">C</div>
</div>
<div>
<div class="obj-node black-node">D</div>
</div>
<div>
<div class="obj-node black-node">E</div>
</div>
<div>
<div class="obj-node black-node">F</div>
</div>
</div>
<div class="label-sm" style="color:var(--accent);margin-top:8px">全部黑色 = 确认存活</div>
<div class="graph-row" style="justify-content:center;margin-top:16px">
<div>
<div class="obj-node dead-node" style="opacity:0.3">G</div>
</div>
<div>
<div class="obj-node dead-node" style="opacity:0.3">H</div>
</div>
</div>
<div class="label-sm" style="color:var(--red);margin-top:8px">仍为白色 = 即将被回收</div>
</div>
</div>
</div>
</div>
</div>
<!-- Phase 4: Concurrent Sweep -->
<div class="phase left">
<div class="phase-marker">
<div class="marker-dot sweep">4</div>
</div>
<div class="text-panel">
<div class="phase-tag sweep-tag">并发 — 与应用并行</div>
<div class="phase-title">并发清扫 Concurrent Sweep</div>
<div class="phase-desc">
<strong>应用再次恢复运行</strong>,同时后台清扫白色对象。<br><br>
<strong style="color:var(--accent3)">清扫逻辑非常简单:</strong><br>
遍历所有内存 span,把仍然标记为白色的对象释放回空闲链表。<br><br>
<strong>Lazy Sweep(懒清扫):</strong><br>
当应用分配新内存时,如果踩到还没清扫的 span,会顺手帮忙清扫。这样大部分清扫工作在 GC 结束后的短时间窗口内完成,不会堆积到下一轮 GC。
</div>
<div
style="margin-top:20px;padding:16px;background:rgba(16,185,129,0.06);border:1px solid rgba(16,185,129,0.15);border-radius:10px;font-size:14px;color:var(--text-muted)">
<strong style="color:var(--accent3)">清扫完成后:</strong><br>
内存全部干净,等待下一轮 GC 触发(通常当堆大小增长到上次的 2 倍时)。
</div>
</div>
<div class="viz-panel">
<div class="viz-card sweep-card">
<div style="text-align:center;margin-bottom:16px">
<span
style="font-family:'JetBrains Mono';font-size:11px;color:var(--accent3);letter-spacing:2px">APPLICATION
RUNNING + SWEEPING</span>
</div>
<div class="obj-graph">
<div class="graph-row" style="justify-content:center">
<div>
<div class="obj-node black-node">A</div>
</div>
<div>
<div class="obj-node black-node">B</div>
</div>
<div>
<div class="obj-node black-node">C</div>
</div>
<div>
<div class="obj-node black-node">D</div>
</div>
<div>
<div class="obj-node black-node">E</div>
</div>
<div>
<div class="obj-node black-node">F</div>
</div>
</div>
<div class="label-sm" style="color:var(--accent);margin:8px 0 20px">黑色对象 — 安全,继续使用
</div>
<div
style="position:relative;text-align:center;padding:24px;border:2px dashed rgba(239,68,68,0.3);border-radius:12px;background:rgba(239,68,68,0.03)">
<div class="graph-row" style="justify-content:center">
<div>
<div class="obj-node dead-node" style="opacity:0.2">G</div>
</div>
<span class="arrow" style="margin:0 24px;color:var(--red)"> </span>
<div>
<div class="obj-node dead-node" style="opacity:0.2">H</div>
</div>
</div>
<div
style="font-family:'JetBrains Mono';font-size:12px;color:var(--red);margin-top:12px;opacity:0.8">
🗑 释放回空闲内存池
</div>
</div>
<!-- Before / After -->
<div
style="display:grid;grid-template-columns:1fr auto 1fr;gap:16px;align-items:center;margin-top:24px">
<div
style="padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;text-align:center">
<div
style="font-family:'JetBrains Mono';font-size:10px;color:var(--text-muted);margin-bottom:6px">
清扫前</div>
<div style="font-size:20px;font-family:'JetBrains Mono';color:var(--text)">8 对象
</div>
<div style="font-size:11px;color:var(--red);margin-top:4px">含 2 个垃圾</div>
</div>
<div style="font-family:'JetBrains Mono';font-size:24px;color:var(--accent3)">→
</div>
<div
style="padding:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;text-align:center">
<div
style="font-family:'JetBrains Mono';font-size:10px;color:var(--text-muted);margin-bottom:6px">
清扫后</div>
<div style="font-size:20px;font-family:'JetBrains Mono';color:var(--accent3)">6 对象
</div>
<div style="font-size:11px;color:var(--accent3);margin-top:4px">全部存活</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!-- end timeline -->
<!-- Summary -->
<div class="summary">
<h2>全流程总览</h2>
<div class="summary-grid">
<div class="summary-card">
<div class="num red">2 次</div>
<div class="desc">STW 暂停次数<br>标记准备 + 标记终止</div>
</div>
<div class="summary-card">
<div class="num cyan">
< 1ms</div>
<div class="desc">每次 STW 耗时<br>只做开关操作,不做遍历</div>
</div>
<div class="summary-card">
<div class="num green">3 色</div>
<div class="desc">白 / 灰 / 黑<br>标记状态三色标记法</div>
</div>
<div class="summary-card">
<div class="num yellow">1 个</div>
<div class="desc">写屏障 Write Barrier<br>并发标记期的唯一保障</div>
</div>
</div>
<div
style="margin-top:40px;padding:24px;background:var(--bg);border:1px solid var(--border);border-radius:12px">
<div style="display:flex;align-items:center;gap:16px;margin-bottom:16px">
<span style="font-size:28px">💡</span>
<span style="font-size:1.1rem;font-weight:600">核心设计思想</span>
</div>
<div style="color:var(--text-muted);font-size:0.95rem;line-height:2">
Go GC 的设计目标是 <strong
style="color:var(--accent)">极低延迟</strong>,而不是极致吞吐。所以它把所有重活(遍历对象图、回收内存)都放到<strong>并发阶段</strong>,而两个
STW 阶段只做最轻量的"开关"操作——开/关写屏障、扫描栈根、清理状态。这就是为什么 Go 程序的 GC 暂停时间通常控制在 <strong
style="color:var(--accent)">< 500 微秒</strong>以内。
</div>
</div>
</div>
</div>
</body>
</html>

效果还不错,UI比较炫酷,并且会展示每秒Token消耗等信息
又问了一个Map的底层原理,这里还是用html展示图像

还想问的时候显示对话达到上限,需要新开,每次体验都是30分钟
浙公网安备 33010602011771号