环境
Memmy 版本:1.1.1(桌面版,darwin-arm64,cn-signed)
系统:macOS 26.5.2 (25F84),Apple Silicon
数据规模(~/.codex/sessions):
会话文件总数:1,687 个(含 .bak-*.jsonl 备份,会被误识别为真实会话)
总大小:20 GB(单文件最大 1.7 GB)
消息总数(扫描器实测):546,102 条,平均每条内容 ~38 KB
问题描述
在「Memory → Sources」中对 Codex 执行全量扫描,每次必现失败。扫描进行约 85–100 秒后停止,界面提示「扫描 Codex 失败,请稍后重试」,进度停留在 546,087–546,102 条消息(即恰好等于 Codex 全部消息总数)。
同一环境下:
其他 Agent(Hermes 1,331 条、DeepSeek Harness 1,637 条、Claude Code 40 条等)扫描正常;
Codex 的增量扫描(默认模式)正常:可导入新增消息并进入摘要阶段;
只有 Codex 全量扫描(mode=full,或首次无水位/无限制时)必现失败。
复现步骤
打开 Memmy 桌面版,进入「Memory → Sources」。
在 Codex 一栏点击全量扫描(或任意触发 sourceId=codex, mode=full 的扫描)。
等待约 90 秒,扫描停止并提示失败。
(可选)通过本地 API 复现:
bash
复制
curl -X POST http://127.0.0.1:51160/api/agent-sources/scan
-H "x-memmy-local-token: <runtime.json 中的 localToken>"
-H "content-type: application/json"
-d '{"sourceId":"codex","mode":"full"}'
轮询 GET /api/agent-sources/scan/status 可观察到: {"active":false,"progress":{"sourceId":"codex","phase":"stopped","current":546102,"message":"Agent source scan stopped"},"completion":{"succeeded":false}}
实际结果
扫描中途停止,completion.succeeded = false,Codex 全量历史(54.6 万条)无法导入。
每次失败时刻对应生成一份崩溃报告:
复制
~/Library/Logs/DiagnosticReports/Memmy Helper-2026-08-27-171433.ips
exception: EXC_CRASH, SIGABRT (Abort trap: 6)
faulting thread 调用栈关键帧:
node::OOMErrorHandler(char const*, v8::OOMDetails const&)
v8::TryCatch::HasTerminated() ...
abort()
即扫描子进程因 V8 JavaScript 堆内存耗尽 而崩溃。 ~/Library/Logs/Memmy/main.log 中每次失败对应一条 memory_source_scan_failed 事件。
预期结果
全量扫描应能完成,或至少分批/流式导入而不崩溃;
失败时 UI 应给出具体错误(如「内存不足」),而不是笼统的「扫描失败」。
根因分析(附源码位置,基于 1.1.1 打包产物 app.asar)
全量收集无上限、全部驻留内存 node_modules/@memmy/backend/dist/src/services/agent-source-service.js → collectSourceMessages(): for await (const message of adapter.scan({...})) { collected.messages.push(message); ... } mode=full 时 maxMessages / maxScanTargets 均为 undefined,54.6 万条消息全部 push 进内存数组,且 conversationIds.includes() 为 O(n²) 线性查重。
导入阶段再次复制放大 同文件 ingestCollectedSource() 中 sortMessagesForIngestion、groupMessagesByConversation、conversationContentHash 均会整表复制。
扫描子进程未调大 V8 堆 node_modules/@memmy/backend/dist/src/adapters/inbound/local-api/routes/agent-sources.js → createScanProcessEnvironment() 仅注入 ELECTRON_RUN_AS_NODE=1,未设置 --max-old-space-size 或 NODE_OPTIONS;fork 出的扫描子进程(agent-source-scan-process.js)使用 V8 默认堆上限(约 2–4 GB)。
内存需求量化 上表 546,102 条消息,仅 content 文本以 UTF-16 计约 40 GB,加上对象结构、排序、分组拷贝约 120 GB,远超默认堆上限,必然 OOM。
次要问题:备份文件被当作真实会话 codex/session-discovery.js 的 listRolloutFiles() 匹配 startsWith("rollout-") && endsWith(".jsonl"),会把 rollout-.jsonl.bak-.jsonl(实测存在 1.3 GB 的 -strip-input-image 备份)也纳入全量扫描,进一步放大数据量。
Memmy-Helper-crash-2026-08-27-171433_副本.md
修复建议
根治:ingestCollected / collect 改为流式导入(分批 add 到 memory service 后再丢弃),避免全量驻留;conversationIds 查重改用 Set。
短期:fork 扫描子进程时注入 NODE_OPTIONS=--max-old-space-size=8192(或按剩余物理内存计算)。
改进:session-discovery.js 排除 .bak-* 文件;扫描失败时通过 completion.results[].errors[].reason 回传真实错误信息到 UI。
环境
Memmy 版本:1.1.1(桌面版,darwin-arm64,cn-signed)
系统:macOS 26.5.2 (25F84),Apple Silicon
数据规模(~/.codex/sessions):
会话文件总数:1,687 个(含 .bak-*.jsonl 备份,会被误识别为真实会话)
总大小:20 GB(单文件最大 1.7 GB)
消息总数(扫描器实测):546,102 条,平均每条内容 ~38 KB
问题描述
在「Memory → Sources」中对 Codex 执行全量扫描,每次必现失败。扫描进行约 85–100 秒后停止,界面提示「扫描 Codex 失败,请稍后重试」,进度停留在 546,087–546,102 条消息(即恰好等于 Codex 全部消息总数)。
同一环境下:
其他 Agent(Hermes 1,331 条、DeepSeek Harness 1,637 条、Claude Code 40 条等)扫描正常;
Codex 的增量扫描(默认模式)正常:可导入新增消息并进入摘要阶段;
只有 Codex 全量扫描(mode=full,或首次无水位/无限制时)必现失败。
复现步骤
打开 Memmy 桌面版,进入「Memory → Sources」。
在 Codex 一栏点击全量扫描(或任意触发 sourceId=codex, mode=full 的扫描)。
等待约 90 秒,扫描停止并提示失败。
(可选)通过本地 API 复现:
bash
复制
curl -X POST http://127.0.0.1:51160/api/agent-sources/scan
-H "x-memmy-local-token: <runtime.json 中的 localToken>"
-H "content-type: application/json"
-d '{"sourceId":"codex","mode":"full"}'
轮询 GET /api/agent-sources/scan/status 可观察到: {"active":false,"progress":{"sourceId":"codex","phase":"stopped","current":546102,"message":"Agent source scan stopped"},"completion":{"succeeded":false}}
实际结果
扫描中途停止,completion.succeeded = false,Codex 全量历史(54.6 万条)无法导入。
每次失败时刻对应生成一份崩溃报告:
复制
~/Library/Logs/DiagnosticReports/Memmy Helper-2026-08-27-171433.ips
exception: EXC_CRASH, SIGABRT (Abort trap: 6)
faulting thread 调用栈关键帧:
node::OOMErrorHandler(char const*, v8::OOMDetails const&)
v8::TryCatch::HasTerminated() ...
abort()
即扫描子进程因 V8 JavaScript 堆内存耗尽 而崩溃。 ~/Library/Logs/Memmy/main.log 中每次失败对应一条 memory_source_scan_failed 事件。
预期结果
全量扫描应能完成,或至少分批/流式导入而不崩溃;
失败时 UI 应给出具体错误(如「内存不足」),而不是笼统的「扫描失败」。
根因分析(附源码位置,基于 1.1.1 打包产物 app.asar)
全量收集无上限、全部驻留内存 node_modules/@memmy/backend/dist/src/services/agent-source-service.js → collectSourceMessages(): for await (const message of adapter.scan({...})) { collected.messages.push(message); ... } mode=full 时 maxMessages / maxScanTargets 均为 undefined,54.6 万条消息全部 push 进内存数组,且 conversationIds.includes() 为 O(n²) 线性查重。
导入阶段再次复制放大 同文件 ingestCollectedSource() 中 sortMessagesForIngestion、groupMessagesByConversation、conversationContentHash 均会整表复制。
扫描子进程未调大 V8 堆 node_modules/@memmy/backend/dist/src/adapters/inbound/local-api/routes/agent-sources.js → createScanProcessEnvironment() 仅注入 ELECTRON_RUN_AS_NODE=1,未设置 --max-old-space-size 或 NODE_OPTIONS;fork 出的扫描子进程(agent-source-scan-process.js)使用 V8 默认堆上限(约 2–4 GB)。
内存需求量化 上表 546,102 条消息,仅 content 文本以 UTF-16 计约 40 GB,加上对象结构、排序、分组拷贝约 120 GB,远超默认堆上限,必然 OOM。
次要问题:备份文件被当作真实会话 codex/session-discovery.js 的 listRolloutFiles() 匹配 startsWith("rollout-") && endsWith(".jsonl"),会把 rollout-.jsonl.bak-.jsonl(实测存在 1.3 GB 的 -strip-input-image 备份)也纳入全量扫描,进一步放大数据量。
Memmy-Helper-crash-2026-08-27-171433_副本.md
修复建议
根治:ingestCollected / collect 改为流式导入(分批 add 到 memory service 后再丢弃),避免全量驻留;conversationIds 查重改用 Set。
短期:fork 扫描子进程时注入 NODE_OPTIONS=--max-old-space-size=8192(或按剩余物理内存计算)。
改进:session-discovery.js 排除 .bak-* 文件;扫描失败时通过 completion.results[].errors[].reason 回传真实错误信息到 UI。