# ProfileMax:基于 CRIU 的 Chromium 浏览器快照实现方案 - 文档类型:实现方案 / PoC 计划 - 状态:已验证(2026-10-20 本机 PoC + node 端到端集成测试通过,实测数据见第 12 节) - 目标路径:`/home/bigcode/data/dev/bun/SerpMax/docs/01_CRIU_BROWSER_SNAPSHOT.md` ## 1. 目标与范围 ProfileMax 需要保存已启动的 Chromium 浏览器运行现场。示例:浏览器已经打开 Google 并完成搜索,创建快照后结束原浏览器;后续恢复时尽可能直接回到原搜索结果页面,避免再次启动浏览器、打开网站、重新执行页面初始化,从而降低重复作业的启动延迟和 CPU 峰值。 本方案采用 Linux + Chromium + CRIU,先验证技术可行性,再开发快照管理层。 ### 1.1 必须实现 - 对 Chromium 完整相关进程树执行 checkpoint / restore。 - 恢复页面当前的内存状态,重点验证 DOM、JavaScript 堆、滚动位置和页面交互。 - 快照成功后可以结束原进程;恢复时不依赖原 Chromium 进程仍然存在。 - 保存快照元数据,校验浏览器版本、启动参数和运行环境。 - 记录创建耗时、恢复耗时、快照大小、内存占用和 CPU 峰值。 - 恢复失败时能报告具体阶段和错误,后续可回退到普通浏览器启动流程。 ### 1.2 明确不作为目标 - **不要求保持原 TCP、HTTP/2、WebSocket 等网络连接。** 恢复后允许浏览器和页面重新建立连接。 - 不保证 Google 或其他网站的服务端会话永远有效。 - 第一阶段不做跨主机迁移、不做快照分叉克隆、不开发通用虚拟机快照系统。 - 不自行实现进程内存快照引擎;使用 CRIU 完成底层检查点与恢复。 - 不修改 Chromium 源码,除非 PoC 证明现有接口无法满足必要条件。 > 网络连接不需要延续,不代表可以直接忽略进程持有的 socket。CRIU 在 dump 时仍必须能处理进程文件描述符及其内核资源。必须通过 PoC 验证连接相关资源的实际处理方式,不能假设不传输 TCP 就一定可以成功 dump。 ## 2. 总体架构 ```text ProfileMax API / Job Manager | v Browser Snapshot Manager | +-- Browser Runtime Manager | +-- Chromium 启动与进程树识别 | +-- 固定 Profile / 启动参数 / 显示环境 | +-- Checkpoint Adapter | +-- CRIU pre-dump / dump / restore 能力探测 | +-- 命令执行、超时、日志和错误归一化 | +-- Snapshot Store | +-- CRIU image 目录 | +-- 元数据与环境指纹 | +-- 完整性检查 | +-- Restore Validator +-- 进程存活检查 +-- 浏览器 DevTools / 页面状态检查 +-- 页面交互与网络重连检查 ``` 建议管理层使用项目现有的 Bun/TypeScript 技术栈实现;CRIU 通过受控子进程调用。若当前项目已有统一任务执行或进程管理模块,应复用,不要另建重复框架。所有 CRIU 命令必须由服务端生成参数数组执行,禁止拼接用户输入到 shell 命令。 ## 3. 关键技术约束 ### 3.1 Chromium 是多进程程序 不能只对 Browser 主进程执行快照。需要识别并纳入同一检查点的相关进程,例如: - Browser 主进程 - Renderer 进程 - GPU 进程 - Network Service / Utility 等子进程 - 与浏览器运行现场相关的其他子进程 PoC 需验证 CRIU 采用正确的进程树入口和权限设置,且恢复后进程关系及 IPC 可用。禁止仅凭一个 PID dump 就认为整个浏览器已被完整保存。 ### 3.2 固定运行环境 第一阶段固定以下条件,减少变量: - 同一台 Linux 主机、同一内核版本与 CRIU 版本。 - 同一 Chromium 二进制版本及启动参数。 - 同一用户、UID/GID、工作目录、环境变量和 Profile 路径。 - 相同的挂载点、字体、共享库、临时目录和必要设备。 - 固定显示模式;优先从无头 Chromium 或固定 Xvfb 环境中选定一种进行 PoC,不要在首轮同时测试多种模式。 - 固定代理配置。代理本身可以在恢复后重新连接,但其配置应保持一致。 快照元数据必须记录上述环境。若恢复环境与快照不兼容,应拒绝恢复并给出明确原因。 ### 3.3 Chromium 沙箱与 GPU Chromium sandbox、namespace、seccomp、GPU 设备、共享内存及文件描述符可能影响 CRIU 兼容性。 - 首轮先使用正常安全配置验证。 - 如果为了定位问题,需要临时关闭 GPU 或在隔离测试环境中调整沙箱,必须作为单独实验变量记录。 - 不得把 `--no-sandbox` 当作生产默认参数,也不得为了通过 PoC 而默默降低生产安全边界。 - 生产部署前必须明确支持矩阵,写明哪些 Chromium 参数和运行模式经过实测。 ### 3.4 网络与 socket 处理 ProfileMax 不需要恢复原 TCP/WS 连接,但进程内仍可能保存 socket 文件描述符、epoll 状态及异步网络请求状态。 实施原则: 1. 不将网络连接连续性纳入快照成功标准。 2. PoC 分别测试 CRIU 默认行为,以及在 CRIU 支持和环境允许时对已建立 TCP 连接的处理行为。 3. 若 dump 因网络文件描述符失败,记录 CRIU 原始错误和对应 FD 类型,再选择可验证的处理方案;不要直接忽略错误。 4. 恢复后,允许应用层重建连接;对已经失效的请求和 WebSocket,页面自身必须能恢复或重新加载相关数据。 5. 如需在恢复后关闭陈旧连接,应采用可验证的浏览器/页面层策略;不要从外部任意关闭 Chromium 的 FD,这可能破坏进程内部状态。 ### 3.5 页面状态边界 进程内存快照的目标是保留运行现场,但不能保证每个网站页面都能无缝续跑: - 页面已渲染的 DOM 和 JavaScript 堆是重点验证项。 - 页面计时器、Promise、Service Worker、后台标签页、扩展进程和浏览器内部任务需要单独测试。 - 恢复后页面可能检测到网络断开、请求失败或登录状态失效。 - 页面现场恢复与网站业务状态恢复是两回事。服务端数据可能已经改变。 ## 4. 快照目录与元数据 建议每个快照使用独立目录,CRIU image 文件和元数据分离管理: ```text data/snapshots/ / criu/ # CRIU 生成的 checkpoint image 文件 manifest.json checkpoint.log restore.log ``` `manifest.json` 建议字段: ```json { "schemaVersion": 1, "snapshotId": "uuid", "createdAt": "ISO-8601", "status": "ready", "browser": { "name": "chromium", "version": "exact-version", "executable": "/usr/bin/chromium", "rootPid": 1234, "launchArgsHash": "sha256" }, "runtime": { "kernelRelease": "exact-release", "criuVersion": "exact-version", "uid": 1000, "gid": 1000, "profilePath": "/data/profiles/example", "displayMode": "xvfb-or-headless", "networkContinuityRequired": false }, "metrics": { "checkpointDurationMs": null, "restoreDurationMs": null, "snapshotBytes": null }, "validation": { "processTreeRestored": false, "pageStateVerified": false, "interactive": false } } ``` 上例仅为结构示意。实际实现必须从运行环境采集真实值,不能硬编码 PID、版本或路径。敏感代理凭据、Cookie 和页面数据不得写入普通日志或 manifest。 ## 5. 生命周期与状态机 建议快照状态: - `creating`:正在执行 checkpoint。 - `ready`:checkpoint 完成,元数据和文件校验通过。 - `restoring`:正在恢复。 - `restored`:进程恢复成功且基础检查通过。 - `failed`:创建或恢复失败。 - `deleting`:正在清理。 创建流程(浏览器关闭前自动快照): 1. ProfileMax 统一管理浏览器关闭入口。任务完成、任务管理器要求关闭或用户主动关闭时,先进入 `closing` 流程;不要等 Chromium 已经开始退出后才监听 `close` 事件。 2. 检查目标浏览器实例和所有权,并确认任务已结束、没有正在执行的关键操作。 3. 记录 Chromium 版本、进程树、启动参数、运行环境及当前作业 URL。 4. 创建临时快照目录并执行 CRIU checkpoint/dump。 5. 收集退出码、stdout/stderr、CRIU 日志和耗时;校验检查点文件完整并写入 manifest。 6. 校验通过后,原子地将快照标记为 `ready`,并将其关联到对应浏览器实例/任务。 7. 只有快照已可靠落盘并标记为 `ready` 后,才完成浏览器关闭流程。注意:常规 CRIU dump 通常会让被 dump 的进程停止/退出,因此应由 CRIU 的实际 dump 语义完成进程收尾,不能再无条件调用 Chromium 的正常关闭。 8. 如果快照失败,记录错误并按配置执行普通关闭;不要把不完整快照标记为 `ready`。若产品要求必须先保留一个仍运行的 Chromium 再正常关闭,需要单独验证 leave-running 模式与 Profile 文件一致性,不能直接把它当作安全默认方案。 关闭事件的实现要求:使用 ProfileMax 自己的统一关闭方法/生命周期钩子作为触发点;浏览器进程已经退出后的 `close`/`exit` 通知只用于清理和记录结果,不用于启动快照。 恢复流程: 1. 校验 manifest、快照文件、版本和运行环境。 2. 确保没有冲突的同一实例正在运行;首版不支持从同一快照并发恢复多个实例。 3. 准备恢复所需的用户、目录、挂载、网络命名空间和显示环境。 4. 执行 CRIU restore,保存日志和耗时。 5. 验证恢复后的进程树、浏览器调试接口(如果启用)、原页面状态及用户交互。 6. 对网络重连进行观察,但不要求旧连接继续存在。 7. 只有验证通过才标记为 `restored`;失败时保留诊断材料,避免自动覆盖原快照。 注意:CRIU 的具体命令行参数、权限要求和网络选项必须以部署机器上安装版本的 `criu --help`、官方文档和 PoC 结果为准。本文不预设某一组命令在所有内核/CRIU 版本上通用。 ## 6. 模块接口建议 管理层可先实现以下内部接口,具体参数根据现有 ProfileMax 代码规范调整: ```ts type SnapshotStatus = | "creating" | "ready" | "restoring" | "restored" | "failed" | "deleting"; interface SnapshotManifest { schemaVersion: number; snapshotId: string; createdAt: string; status: SnapshotStatus; browser: { name: "chromium"; version: string; executable: string; rootPid: number; launchArgsHash: string; }; runtime: { kernelRelease: string; criuVersion: string; uid: number; gid: number; profilePath: string; displayMode: string; networkContinuityRequired: false; }; } interface CheckpointResult { snapshotId: string; durationMs: number; snapshotBytes: number; logPath: string; } interface RestoreResult { snapshotId: string; durationMs: number; restoredPids: number[]; validationPassed: boolean; } interface CheckpointAdapter { checkCapabilities(): Promise<{ available: boolean; criuVersion?: string; reasons: string[]; }>; checkpoint(browserRootPid: number, snapshotDir: string): Promise; restore(snapshotDir: string): Promise; } ``` 这些接口是设计草案,不代表项目中已经存在对应模块。需要先查看 ProfileMax 当前目录结构和现有进程管理实现,再决定最终落点。 ## 7. PoC 实施计划 ### P0:环境检查 - 确认 Linux 发行版、内核版本、CRIU 版本及所需权限。 - 运行 CRIU 自检,并保存完整输出。 - 检查 Chromium 的实际进程树、命名空间、打开的 FD、共享内存和设备依赖。 - 记录当前 Chromium 版本、启动参数和运行模式。 交付物:环境报告、CRIU capability 报告、浏览器进程树样本。 ### P1:最小 checkpoint / restore - 启动 Chromium 并打开固定测试页面。 - 在页面内创建可验证的 JavaScript 状态标记,例如计数器、随机 token、滚动位置和 DOM 文本。 - 执行 checkpoint,确认原实例已按预期停止或退出。 - restore 后读取页面标记,验证其与 checkpoint 前一致。 - 检查页面是否可点击、输入和滚动。 交付物:可重复执行的测试脚本、CRIU 日志、成功/失败原因。 ### P2:真实搜索页面 - 打开 Google 并执行固定关键词搜索,按正常流程完成测试任务。 - 任务完成、浏览器准备关闭时,由 ProfileMax 关闭流程触发快照;不使用定时快照,也不需要单独监听页面稳定事件。 - 快照完成并可靠落盘后,按 CRIU dump 的实际语义结束原进程,再执行恢复测试。 - 验证 URL、DOM、滚动位置和页面交互。 - 观察网络重连后的页面行为;不把旧 TCP/WS 保持连接作为成功条件。 交付物:真实网站验证记录。若网站行为不稳定,使用本地测试页面作为可重复基线,并将网站测试作为补充。 ### P3:基准测试 至少重复 20 次,分别测量普通冷启动和快照恢复: | 指标 | 冷启动 | CRIU 恢复 | |---|---:|---:| | 总耗时 P50 / P95 | 测量 | 测量 | | CPU 峰值 | 测量 | 测量 | | 恢复后可交互耗时 | 测量 | 测量 | | 快照体积 | 不适用 | 测量 | | 失败率 | 测量 | 测量 | 必须统一测试条件:相同主机、Chromium 版本、Profile、页面、代理和资源状态。单次结果不能作为结论。 ### P4:管理器封装 只有 P1/P2 证明可行后再实施: - snapshot create / restore / inspect / delete。 - 状态机和并发锁。 - 日志、错误分类、超时和取消。 - 快照容量限制及过期清理。 - 环境兼容性校验和失败降级。 - 权限隔离,避免普通用户对任意系统进程执行 dump/restore。 ## 8. 验收标准 首阶段必须全部满足: 1. 能对目标 Chromium 进程树成功 checkpoint。 2. 原浏览器进程停止后,能够从快照恢复。 3. 恢复后原页面的验证标记、URL、主要 DOM 状态及滚动位置符合预期。 4. 页面可继续交互,且允许网络连接重新建立。 5. 失败时能够通过日志定位到具体 CRIU 错误或资源依赖。 6. 测得冷启动与恢复的耗时、CPU 峰值、快照大小和失败率。 性能目标在取得基线数据后设定,不预先承诺快照恢复一定比冷启动快。快照读取、内存恢复和页面恢复验证都可能消耗显著的磁盘 IO 与 CPU。 ## 9. 安全与运维要求 - 快照可能包含 Cookie、认证令牌、页面内容及其他敏感内存数据,按敏感数据保护。 - 快照目录仅允许浏览器运行用户和快照管理服务访问,权限默认最小化。 - 不在日志中输出 Cookie、Authorization、代理密码或页面表单内容。 - 只允许管理器操作其登记的 Chromium 进程,不接受任意 PID 的外部请求。 - CRIU dump/restore 使用最小必要权限;如需 root 权限,限定服务边界并记录审计日志。 - 删除快照时清理完整目录,并记录清理结果。 - 版本、内核或启动参数不兼容时拒绝盲目恢复。 ## 10. 参考资料 - CRIU: - CRIU 官方文档: - CRIU 使用手册: - Podman checkpoint/restore(用于参考容器集成方式): ## 11. 当前结论 采用“CRIU 底层 + ProfileMax 自有管理层”的路线。第一阶段只交付 PoC,不提前承诺 Chromium 全进程树一定可恢复。优先验证真实运行环境中的沙箱、GPU、共享资源和 socket 处理。TCP/WS 连续性不是验收目标;进程仍需正确处理网络相关 FD,恢复后允许应用重新连接。PoC 通过后再扩展为多实例快照管理。 ## 12. 实测结论与落地记录(2026-10-20) ### 12.1 环境与实测数据 - 环境:Zorin OS 18.1(Ubuntu noble 基),内核 7.0.0-31-generic,veil-chromium 153.0.8010.52; CRIU 4.2(源码编译,`/usr/local/bin/criu`,文件能力 `cap_sys_ptrace,cap_sys_admin,cap_net_admin+eip`, 非 root 可用,免改 ptrace_scope)。 - PoC(直启 chrome → baidu 搜索页 → dump → restore): | 指标 | 实测值 | |---|---| | 冷启动(进程拉起 → CDP 就绪) | ≈ 0.6s | | dump(9 进程树,RSS ≈ 1.13GB) | ≈ 1.3s,镜像 ≈ 354MB(397 个 .img) | | restore(detached) | ≈ 0.36s | | 现场校验 | URL/标题/JS 堆标记/滚动位置/搜索结果 DOM/localStorage 全部一致,`navigator.onLine=true` | | 可交互 | 恢复后二次搜索成功(网络自动重连) | - node 端到端(经 ProfileMax API:创建快照 Profile → 启动 → 搜索 → 停止自动 dump → 再启动): 停止含 dump ≈ 1.3s;再次启动 ≈ 0.4s 且 `restored:true`,CDP 端口原样恢复,现场校验同上全绿 (复测脚本 `node/scripts/criu-poc.ts`、`node/scripts/criu-e2e.ts`)。 ### 12.2 关键结论(实测定论) 1. **沙箱与 CRIU 的结构性冲突**:criu 拒绝对「非根进程自建的嵌套 PID namespace」执行 dump (`CLONE_SUBNS` 仅含 mount/net),而 chromium namespace 沙箱的 zygote/渲染进程恰在嵌套 pidns 中。 → **快照模式 Profile 启动时显式追加 `--no-sandbox`**(browser.manager `snapshotSandboxArgs`); 生产节点为 root 容器,ProfileMax 本就强制 `--no-sandbox`,此处仅影响非 root 环境,非全局降级。 2. **仅支持 headless**:有头模式连接的 X11/Wayland socket 是树外 STREAM unix socket, criu 的 `--ext-unix-sk` 仅支持 DGRAM 外部连接 → 有头实例停止时不做快照(回退常规关闭)。 3. **D-Bus 必须「干净失败」隔离**:chrome 对已建立后断开的 dbus 连接会 FATAL ("D-Bus connection was disconnected. Aborting.")。快照模式启动 env 将 `DBUS_SESSION_BUS_ADDRESS`/`DBUS_SYSTEM_BUS_ADDRESS` 指向 `unix:path=/nonexistent-bus` (与生产容器无 bus 的现实一致);地址格式非法(如 `/dev/null`)会导致导航失败,不可用。 4. **crashpad handler 在树外**:chrome 会把 handler daemonize 到进程树外(subreaper 接管), 其 SEQPACKET socketpair 端为树外对端。已给 criu 打补丁:dump 允许外部 STREAM/SEQPACKET, restore 侧对非 DGRAM 外部对端跳过 connect(以「未连接」语义恢复,客户端优雅降级); 补丁内容两处(criu/fsnotify.c 悬空 inotify watch 跳过 + criu/sk-unix.c 外部 socket 放行), 生产镜像需携带补丁版 criu。 5. **chromium 共享内存临时文件**(`.org.chromium.Chromium.*`,实测 4MB 起步)远超 criu 默认 1MB ghost 限额 → dump/restore 统一 `--ghost-limit=512MB`(env `CRIU_GHOST_LIMIT_MB` 可调)。 6. **dump 参数**:`--file-locks --tcp-close --ext-unix-sk --ghost-limit=N [--unprivileged]`; `--tcp-close` 表示已建 TCP 连接按「关闭」落镜像(符合 1.2 节「不要求连接连续性」), 恢复后由页面/浏览器自行重连,实测 baidu 页面正常。 7. **启动方式约束**:快照 Profile 由本服务直启(setsid 保证 session leader + 显式 `--user-data-dir`),不经 playwright 管道(管道对端在树外无法 dump);CDP 经 connectOverCDP 挂接,停止时 playwright 句柄 close() 仅断连不杀进程。 8. **参数哈希与端口绑定**:dump 时将完整启动参数(含 `--user-data-dir` 打头)哈希入 manifest, restore 前重算比对,任一不一致拒绝恢复回退冷启动;impersonate MITM 端口记入 manifest, 恢复时 `ensureImpersonate` 优先复用同端口(浏览器重连无缝),端口被占则拒绝恢复。 9. **陈旧 DevToolsActivePort**:dump 后该文件残留,直启前必须删除,否则 CDP 就绪探测 可能打在死端口上(实测踩坑)。 10. **criu 单次操作超时 180s**,dump/restore 失败不重试:回退常规关闭/冷启动, 失败快照保留 `failed` 状态与日志供诊断(manifest.json / dump.log / restore.log)。 ### 12.3 落地范围(本版) - Profile 新增 `snapshot.enabled` 配置(admin「快照模式」开关,缺省关闭;仅 veil + headless 生效); - 停止浏览器时自动 checkpoint(存储快照抓取先于 dump),启动时优先 restore 并回写 CDP/条目; - 节点 API:`GET/DELETE /profiles/:id/snapshot`;admin 中继同路径 GET/DELETE + PUT 快捷开关; - admin 概览卡:快照(含大小)/ 自动CF挑战 / 自动挑战 reCAPTCHA 三开关同行; - 快照目录:`//snapshot/`(manifest.json + criu/ 镜像 + dump/restore 日志), 随 Profile 删除一并清理;同一 Profile 仅保留最近一次快照。 ## 13. 镜像压缩与 USER_DATA 清理(2026-10-21,node v0.38.0 / admin v1.55.0) ### 13.1 镜像压缩(zstd 后处理) CRIU 4.x 核心已移除内建压缩选项(旧版 `-z/--compress` 不存在,`criu-image-streamer` 需额外组件), 采用「dump 后 zstd 压缩大镜像 / restore 前解压还原」的后处理方案(snapshot.manager): - dump 成功后(进程已退出)对镜像目录中 >1MB 的 `*.img` 逐文件 `zstd -3 -T0` 压缩, 压缩成功才删原文件,单文件失败保留原样不阻塞;`SNAPSHOT_COMPRESS=off` 可整体关闭。 - restore 前把 `*.img.zst` 解压还原(criu 不识别压缩镜像),耗时记入 manifest `metrics.decompressDurationMs`;压缩前/后体积分别记 `snapshotBytesRaw`/`snapshotBytes`。 - 实测(同环境同场景,baidu 搜索现场,两轮): | 指标 | 压缩前(10-20 基线) | 压缩后(10-21 实测) | |---|---|---| | 快照镜像大小 | 308~312MB | **67.5~70.6MB(约 4.4x 缩小)** | | dump 耗时 | ≈1.0~1.3s | ≈1.0~1.3s(不变) | | 停止总耗时(含 dump+压缩) | ≈1.2~1.3s | ≈2.4s(压缩约 +1.1s,zstd -3 -T0) | | restore(criu 自身) | ≈0.3s | ≈0.3s(不变) | | restore 前解压 | — | ≈0.58s | | 再次启动总耗时 | ≈0.43~0.58s | ≈1.11~1.16s(解压 +0.6s) | | 现场校验(8 项) | 全绿 | 全绿(URL/标题/JS 标记/滚动/localStorage/结果数/在线/二次搜索) | 结论:以「每次停止 +≈1.1s、每次恢复 +≈0.6s」换「磁盘占用 -77%」,默认开启; 磁盘敏感场景收益显著,对恢复可用性无影响。 ### 13.2 USER_DATA 静态缓存清理 - **自动清理(默认开启)**:浏览器停止时实测 USER_DATA 体积(关闭前采样)超过 `USERDATA_CLEAN_THRESHOLD_MB`(默认 100MB)→ 进程完全退出后软清理静态缓存 (cache.manager `autoCleanOnStop`);清理后体积才回传 admin(profiles.user_data_size)。 - **软清理范围(CACHE_DIRS)**:根级 + `Default/` 子目录双布局——HTTP Cache、Code Cache、 GPUCache、Dawn/GrShader/Graphite 缓存、Media Cache、Shared Dictionary、组件 crx 缓存等; Cookie/LocalStorage/IndexedDB/Service Worker/登录态一律保留(实测主要占用 `Default/Cache` + `Default/Code Cache`,约占 USER_DATA 80%)。 - **手动清理**:节点 `POST /profiles/:id/cleanup`(admin 中继 `POST /api/profiles/:id/cleanup`, Profile 详情页「编辑」与「复制」之间的「清理」按钮):软清理 + **删除现有 CRIU 快照** (快照镜像含缓存页,restore 会原样还原缓存,不删等于没清;下次停止自动重建快照); 浏览器运行中节点拒绝(`CACHE_CLEAR_FAILED`,提示先停止)。返回 before/after/freedBytes 与 snapshotDeleted,前端 toast 展示释放体积。 - 验证:130MB 假缓存(Default/Cache)触发清理释放 120MB,Cookie/LocalStorage 保留; 50MB 未触发;E2E 全流程(含手动清理后快照 bytes=0)通过。 ### 13.3 启动方式对比:正常冷启动 vs 快照恢复(到达同一现场) 口径:从 `POST /browser/start` 发起,到「baidu 同一关键词搜索结果页 DOM 已渲染」为止 (CDP 连接与现场确认均计入);基准脚本 `node/scripts/criu-bench-compare.ts`,两轮实测: | 阶段 | 冷启动(非快照) | 快照恢复 | |---|---|---| | 启动 → CDP 就绪 | 0.80~0.96s | 0.99~1.51s(含解压≈0.6s + restore≈0.3s) | | 导航加载搜索结果 | 2.52~4.08s(随网络波动) | 0(现场已在,免导航) | | 现场确认 | 0.08~0.11s | 0.04~0.32s | | **到达同一现场总计** | **3.69s / 4.44s** | **1.18 / 1.40 / 1.49 / 1.59s(均值 ≈1.4s)** | | 现场一致性 | — | 4/4 轮 URL/标题/结果数完全一致 | | **加速比** | — | **2.86x / 2.88x(两轮稳定)** | 附:快照 Profile 自身冷启动(3.61s/5.14s)与普通 Profile 无差异,快照模式不拖累冷启动; 本组 dump 耗时 1.7~3.3s、快照 60.4~70.9MB(压缩后),dump 耗时随当时浏览器内存占用浮动。