# GPU 机硬挂首次崩溃取证报告

> 取证时间：2026-09-28 10:49（机器 10:47 重启后由监督脚本**自动抓取**）
> 原始现场：`崩溃取证/recovery_20260928_104833.txt`（41 KB）
> 意义：**这是这台机器 6 次硬挂以来第一次拿到崩溃现场**——此前所有记录都写着「没有崩溃捕获能力」

---

## 一、结论先说

**找到了高度可疑且可操作的元凶：宿主机内存压力（kernel-level memory pressure）+ 缺失 `--disable-pinned-memory`。**

这不是"随机玄学"，是有日志证据的：

1. 上一次启动的内核日志里出现 **4 次内核级内存压力告警**：

   ```
   Sep 28 03:51:14 zywpc systemd-journald[1182]: Under memory pressure, flushing caches.
   Sep 28 03:52:50 zywpc systemd-journald[1182]: Under memory pressure, flushing caches.
   Sep 28 04:19:31 zywpc systemd-journald[480]:  Under memory pressure, flushing caches.
   Sep 28 04:56:30 zywpc systemd-journald[1182]: Under memory pressure, flushing caches.
   ```

2. **日志在 `05:04:39` 戛然而止** —— 没有 panic、没有 Xid、没有 GSP 报错、没有 OOM-killer、没有正常关机记录。
   **「日志直接断掉」= 内核冻结（hard freeze）**，与「整机硬挂」的现象完全吻合。

3. 最后一次内存压力告警（04:56:30）之后 **8 分钟**机器就冻死了。

4. **关键是：当时那个 ComfyUI 实例的启动参数里没有 `--disable-pinned-memory`** ——
   而这正是 2026-09-15 取证报告查出的病因：ComfyUI 默认会 pin 住按公式算出来的
   **≈27.1 GiB「不可换页」宿主内存**，而本机只有 **30 GiB** 物理内存。

---

## 二、现场数据

### 2.1 机器基本盘

| 项 | 值 |
|---|---|
| 物理内存 | **30 GiB** |
| Swap | **71 GiB**（`/swap.img` 8G + `/swap2.img` 64G），但**使用 0 B** |
| GPU | RTX 5060 Ti 16 GB，驱动 610.43.02 |
| 内核 | 6.8.0-142-generic |
| `kernel.panic` | 10 |
| `kernel.panic_on_oops` | 0 |
| `kernel.hung_task_panic` | **1** |
| `kernel.hung_task_timeout_secs` | **300** |

> ⚠️ 注意：`hung_task_panic=1` + 300s 本应让内核在任务挂起 5 分钟后 panic 并 10 秒后自动重启，
> 但**它没有触发**（日志里没有 panic 记录，也没有自动重启）——
> 说明冻结得太彻底，连 hung_task 检测器都没能跑起来。这解释了为什么"必须人工断电"。

### 2.2 启动记录（journald **是持久化的**）

```
-4  ...  Fri 2026-09-25 18:57:47 → Sun 2026-09-27 03:32:30
-3  ...  Sun 2026-09-27 03:35:35 → Sun 2026-09-27 20:35:32
-2  ...  Sun 2026-09-27 20:38:51 → Mon 2026-09-28 02:26:57   ← 第一次硬挂（02:26）
-1  ...  Mon 2026-09-28 02:52:05 → Mon 2026-09-28 05:04:39   ← 第二次硬挂（05:04）
 0  ...  Mon 2026-09-28 10:47:42 → （当前）
```

**这推翻了运维记录里"没有崩溃捕获能力"的旧结论** —— journald 有持久化存储
（`/var/log/journal` 存在，`journalctl --list-boots` 可列出 5 个历史启动），
以前只是没人在恢复后第一时间去读。现在监督脚本会自动读。

> 注意 `-2` 段的结束时间 02:26:57 —— 但机器重启是 02:52:05。
> 也就是 **02:26:57 冻死 → 直到 02:52:05 才重启**（中间 25 分钟无人处理）。
> 这与我观察到的时间线吻合：我 02:50 发现不可达，报告后你断电重启，02:52 起来。

### 2.3 内存压力时间点与生成任务的对应关系

| 内存压力告警 | 当时在做什么 |
|---|---|
| 03:51:14 | 镜01（Pass2 采样中，03:49 提交） |
| 03:52:50 | 镜01 |
| 04:19:31 | 镜01 刚出片（04:17）、镜02 刚提交（04:18） |
| 04:56:30 | 镜03（04:50 提交） |
| **05:04:39** | **镜03 生成中 → 整机冻死** |

**每一次内存压力告警都落在生成任务的时间窗内**，不是巧合。

### 2.4 其它发现：Docker 的 snapshotter 告警（**已核实，影响有限**）

> ⚠️ **更正**：本节初版写成「Docker 在反复解包/拉取镜像」，**这个描述不准确**。
> 复核后确认：`comfyui_persist` 容器**7 周前就已 Exited(127)**，镜像 `nvcr.io/nvidia/pytorch:25.12-py3` 是**早已存在的本地镜像**；
> 那些告警是 Docker 29.3.0 的 containerd-snapshotter 集成**计算镜像体积失败**时报的 warning（`Canceled: context canceled`），
> **不是网络拉取、也不持续占用内存**。当前启动(0)里共 18 条，绝大多数集中在 dockerd 启动那几秒。
> 保留在此仅为如实记录，**它不太可能是硬挂主因**。

原始告警样貌：

```
03:34:54 dockerd: failed to calculate snapshot usage ... "Canceled: context canceled"
03:52:45 dockerd: 同上
03:56:21 dockerd: 同上
04:26:37 dockerd: 同上
04:43:49 dockerd: 同上
04:56:29 dockerd: 同上
```

当前在跑的容器：
```
homepage                ghcr.m.daocloud.io/gethomepage/homepage:latest   Up
mumuainovel             mumujie/mumuainovel:latest                       Up
mumuainovel-postgres    postgres:16-alpine                               Up
open-web-search         ghcr.io/aas-ee/open-web-search:latest           Created
comfyui_persist         nvcr.io/nvidia/pytorch:25.12-py3                 Exited (127)
```

结论：这是 **Docker daemon 的健康噪音**，不是内存压力源。
在 30 GiB 机器上跑 H3 时它不会带来实质负担，**无需处理**。

（真正需要盯的是 3.1 的 `--disable-pinned-memory` —— 已修复，且重启后内存压力告警计数为 **0**。）

---

## 三、修复与缓解

### 3.1 已生效（监督脚本里）

ComfyUI 现已以此参数启动，**已实测进程命令行确认**：

```
main.py --listen 0.0.0.0 --port 8189 --lowvram --force-fp16 --reserve-vram 1.0
        --fast-disk --cache-lru 2
        --disable-pinned-memory        ← 关键！去掉那 ≈27 GiB 的不可换页池
        --preview-method none
```

对比：**本次两次硬挂时用的命令没有 `--disable-pinned-memory`**（我照抄了 09-25 监督脚本以外的旧命令）。
这是本次排查最重要的操作性发现。

### 3.2 建议的进一步缓解（需要你决定，我没有擅自做）

| # | 措施 | 效果 | 风险 |
|---|---|---|---|
| 1 | **生成期间停掉非必要 Docker 容器**（`homepage`、`mumuainovel`、`mumuainovel-postgres`） | 直接释放内存，且消除镜像解包抖动 | 会让这三个服务短暂不可用 |
| 2 | ~~查清谁在反复拉 PyTorch 镜像~~ | **已核实无需处理**（见 2.4 更正） | — |
| 3 | 给 ComfyUI 加 **RAM 哨兵**（`ram_guard.sh`，09-25 已有） | 内存越线时主动干预 | 需确认脚本存在于 GPU 机 |
| 4 | **降载**（Pass2 步数 8→6、分辨率 768P→640P） | 缩短单镜满载窗口 | 画质略降 |

> 我倾向先只做 3.1（已做）+ 观察一轮：既然 `--disable-pinned-memory` 正是 09-15 查出的病因，
> 而本次两次硬挂都缺这个参数，**很可能补上之后就能稳定跑完**。
> 如果补上后仍挂，再上 3.2 的 1/2/4。

---

## 四、与历史结论的关系

运维记录 `2026-09-25` 曾下结论「**该机在 H3 长时满载下会随机整机硬挂，与配置/软件路径无关**」。
本次取证**部分修正**了这个结论：

- 该结论成立的前提是「已按 09-15 修复配好参数」。但在**本次两次硬挂中，`--disable-pinned-memory` 是缺的**，
  所以这两次不能用来支持"与配置无关"。
- 现在有直接证据（4 次内核内存压力告警 + 日志冻结式终止）指向**内存压力**，
  这与 09-15 的 pinned-memory 结论一致，而非"随机硬件故障"。
- 若补上参数后仍复现，才应回到"硬件层面"（此时应重点看 3.2 的第 2 项：Docker 抖动，
  以及考虑换更大内存/关掉 swap 之外的干扰）。

---

## 五、监督脚本本次的实际表现（全自动，无需人工）

```
10:47  机器重启恢复
10:48  监督脚本第 324 轮探活成功
10:48  自动触发 capture_after_recovery.sh（本报告的数据来源）
10:49  取证落盘（41 KB）
10:49  发现 ComfyUI 未就绪 → 自动拉起（带 --disable-pinned-memory）
10:53  ComfyUI 就绪（200）
10:53  自动开始断点续跑，扫到 S01/S02 已存在 → 跳过
10:53  提交 S03（上次被打断的那一镜）→ 采样中（GPU 14.3GB / 98%）
```

**从机器恢复到继续出片，全程 6 分钟，零人工干预。**

---

## 六、产物位置

| 内容 | 路径 |
|---|---|
| 本报告 | `dl-hub/06-ComfyUI-H3运维记录/崩溃取证/2026-09-28-首次崩溃取证报告.md` |
| 原始现场 | `dl-hub/06-ComfyUI-H3运维记录/崩溃取证/recovery_20260928_104833.txt` |
| 取证脚本 | `~/.tools/capture_after_recovery.sh` |
| 监督脚本 | `~/.tools/mv_aicg3d_supervisor.sh` |


---

# ⚠️ 重要修正（2026-09-28 11:50 补录）

## 一、`--disable-pinned-memory` **没能阻止第三次硬挂**

本报告第三节把「内存压力 + 缺失 `--disable-pinned-memory`」当作元凶并断言
"很可能补上之后就能稳定跑完"。**这个结论下得太早，已被证伪。**

**第三次硬挂事实**：

| 项 | 值 |
|---|---|
| 时间 | 2026-09-28 约 **11:33**（第 3 次硬挂） |
| 当时在跑 | 镜03（用**新的单人正面参考图**重跑） |
| ComfyUI 参数 | **已含 `--disable-pinned-memory`**（进程命令行已核实） |
| 本启动内存压力告警计数 | **0**（`journalctl -b 0 \| grep -c "memory pressure"` = 0） |
| 距该批次开始 | **仅约 3 分钟** |

→ **在内存压力为 0、修复参数已生效的情况下依然硬挂**，说明内存压力**不是（唯一）病因**。

## 二、第三次硬挂的形态与"长时满载"假设不符

此前 09-25 记录与本次前两次都表现为"跑了一段时间后挂"。但第三次：

- 批次 **11:29:56** 开始 → **11:33 左右**失联，**只有约 3 分钟**
- 这 3 分钟正好是 **模型加载阶段**（日志里模型加载约需 2~3 分钟，`Model Initializing ...`）
- 09-25 记录的死亡位置也是 "S03 的 `Model Initializing ...`"，**同样是加载阶段**

**新假设：崩溃与「大模型反复加载/卸载」的内存与 IO 尖峰有关，而不是"跑久了才挂"。**

这条假设有一个可疑的诱因：第三次硬挂前，我**中断了 S04 并清空了 ComfyUI 队列**
（因为要用新参考图重跑）。该操作会让已驻留的 20GB UNET + 15GB 文本编码器被释放，
紧接着新批次又要重新加载它们 → **一次剧烈的内存/IO 尖峰**。
**这可能是我自己制造的触发条件。**

## 三、修正后的处置原则

| # | 原则 | 原因 |
|---|---|---|
| 1 | **不要再随意中断/清空 ComfyUI 队列** | 会强制大模型重新加载，制造内存/IO 尖峰 |
| 2 | 保持 `--disable-pinned-memory`（继续保留） | 即便不是唯一病因，它消除了 27GB 不可换页池，没有坏处 |
| 3 | 参考图等**改动必须在批次间隙做**，不要在采样中途打断 | 同 1 |
| 4 | 下次恢复后**先取证**（监督脚本已自动做），重点看**死前最后动作是否在模型加载** | 验证新假设 |
| 5 | 若确认是加载尖峰：考虑把 H3 模型常驻（不卸载）、或改用更小的模型档 | 降低尖峰 |

## 四、对用户的影响

第 3 次硬挂同样需要**人工断电重启**。监督脚本已在守护，恢复后会自动取证+拉起+续跑。

**当前进度仍为 2/45**（S01、S02 有效；S03 用新参考图重跑时被这次硬挂打断，仍需重跑）。

## 五、诚实说明

我在上一轮把"内存压力"当成了确定结论并向用户断言"很可能补上就能稳定跑完"，
**这是过早的结论**。本机 6 次硬挂的原因目前**仍未确认**；
内存压力是本启动里**唯一抓到的内核级异常**，但它显然不足以解释全部。
后续每轮恢复都会自动取证，累积样本后再下结论。
