diff --git a/HANDOFF.md b/HANDOFF.md index e21b6f9..c6aa80c 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -117,6 +117,8 @@ make macos-offline-tests ## 9. 会话日志(最近) +- 2026-11-13 / Claude Code(air):**内存口径已定(ADR-338)**。`memory-gate.sh` 改以稳态存活堆 `heap_live_mb` 判定,门槛 24 MiB,不再按学习区分档;「私有已提交」与 footprint 只作参考;新增 `ANALYZE_ONLY=1` 复核旧快照。对报告 265 的 5 组快照(23 轮)重判全部 PASS(20.1–21.2 MiB)。取代 ADR-263/292/312 的口径与门槛。**发版阻塞里的内存一项已解除**;剩余:PR #274(ADR-337)未合并、其两项修复未实机确认,升版本号,DMG 完成页。本条与上一条文档提交都在本地 `dev`,等 #274 合并后再推。 +- 2026-11-13 / Claude Code(air):**重启后内存重测(报告 265 §4.3):无回归,门禁口径失效**。swap 0、负载 1–4,新旧包各 5 轮:稳态「私有已提交」新 37.4 / 37.3、旧(1.2.1 发布版)37.5 / 37.3,两者都 5 轮全超 34 MiB;存活堆都是 20.1–20.2 MiB。该口径随内存压力反向变化(swap 满时 31–34,swap 空时 35–37.6),量的是系统状态。**待用户裁定**:把判定口径换成 `heap_live_mb`(需 ADR)。已装回新包 `3e428b7`。PR #274(ADR-337)CI 全绿(首跑 `macos` 是没分到运行机被取消,重跑通过),**未合并、等用户授权**;本条文档提交暂留本地,等 #274 合并后再推,免得重跑 CI。 - 2026-11-12 / Claude Code(air):**用户实机反馈两处缺陷 → ADR-337**。① `12:30` 得到 `12;30`:带 Shift 的标点到核心时是未加 Shift 的字符 → 宿主改用 `typedScalar`(按键码 + Shift 重算)。② 拼音上屏后五笔码提示不出现:探针复现属实(宿主无浮层变化、诊断日志无取光标记录),进程内重放逻辑通过,**根因未定位**;改为上屏前候选快照并给提示路径每个分支加诊断日志。用户确认练习「字根」「词组」题型正常。四道检查全绿,新增 3 条真机样本(共 26 条)。**两项修复都未在真机确认**:等本批 PR 合并出包后装机,先看 `lampyris-hud-diag.log` 里的 `hint skip=/show=`。内存门槛按用户决定:重启电脑后重测再定。DMG 完成页仍未验证。 - 2026-11-12 / Claude Code(air):**首键 +4.6 MiB 归因完成(报告 265 §4.2),不改产品代码**。读 `vmmap` 的 MALLOC ZONE 存活分配:首键时点只有两种状态——5.2 MiB(无会话存活,数据已随 `Weak` 缓存释放)或约 19 MiB(有会话存活);新包 8 轮里 3 轮撞上后者、旧包 5 轮 0 轮(偶然概率约 20%),无会话的轮次新旧完全相同。稳态存活堆新包 +0.5 MiB(21.0 vs 20.5)。`memory-gate.sh` 新增参考字段 `heap_live_mb` / `heap_allocations`。副产结论:冷首键 ~30 ms 很可能来自「最后一个会话释放后重新读盘解析」,与本批无关,是否常驻数据需 ADR。PR #273 待合并;已装仍是 `3e428b7`。 - 2026-11-12 / Claude Code(air):**内存新旧包 A/B(报告 265 §4.1)**。新→旧(1.2.1 发布版)→新,各经 `install.sh` 覆盖安装。稳态私有中位数:`six-words` 新 31.8 / 旧 33.0,`idle-8s` 新 31.6 / 旧 31.0 → **稳态无回归**;但学习区开启时两者都贴 34 MiB 门槛(旧包最高 33.7,新包 11 个样本 2 个超限,同包三次运行 FAIL/PASS/FAIL)。**新发现:首键时点新包 +4.6 MiB(27.8 vs 23.2),未归因。** 结束状态:已装新包 `f38e4e1a…`(`3e428b7`)、输入源萤火虫、config 未变;`updates/` 多出两份 A/B 产生的备份(`…T105406Z`、`…T110001Z`)未删。待用户裁定:门槛是否重测调整、首键内存是否发版前归因。 diff --git "a/docs/MVP\344\272\247\345\223\201\351\252\214\346\224\266\346\240\207\345\207\206.md" "b/docs/MVP\344\272\247\345\223\201\351\252\214\346\224\266\346\240\207\345\207\206.md" index 150198c..e6710e4 100644 --- "a/docs/MVP\344\272\247\345\223\201\351\252\214\346\224\266\346\240\207\345\207\206.md" +++ "b/docs/MVP\344\272\247\345\223\201\351\252\214\346\224\266\346\240\207\345\207\206.md" @@ -20,7 +20,7 @@ MVP是首个准备正式分发的macOS产品版本:核心输入功能齐全、 | 交互完整 | 首次安装可照说明完成;设置分组连续、名称清楚;词库错误保留输入、可纠错;反馈/复制结果明确;错误不反复打断 | 用户从安装到输入、修改设置、纠错、反馈、升级/卸载完整任务走查;不要求新增引导弹窗或助手 | | 视觉良好 | 候选/设置/词库/版本窗口/菜单风格统一;选中、首选、悬停、错误状态可辨;布局无重叠/不可操作截断;亮暗与Retina/非Retina下文字清楚,图标实际显示合格 | 完整界面状态截图和人工评审;正文/次要文字实际合成背景对比度≥4.5:1,不能以全图极值证明;长词可读且提交完整文本 | | 可访问性 | 核心操作可用键盘完成;VoiceOver能识别候选/选择/设置标签,辅助动作选词不夺走客户端焦点 | 原生AX及VoiceOver实机结果;安全测试环境中复验 | -| 性能与体积 | 按键→候选p95<16ms,正常输入稳态常驻内存≤30MB,安装包≤15MB;无可感知持续卡顿或异常空闲负载 | 真实IMK与FFI分别记录;明确计时边界/环境/预热/样本数;冷简繁与面板另报告,不用单点或不同内存单位混算 | +| 性能与体积 | 按键→候选p95<16ms,正常输入稳态常驻内存≤30MB(MVP 时的口径;自 ADR-338 起门禁改为稳态存活堆 ≤24 MiB,原口径随系统内存压力漂移,只作参考),安装包≤15MB;无可感知持续卡顿或异常空闲负载 | 真实IMK与FFI分别记录;明确计时边界/环境/预热/样本数;冷简繁与面板另报告,不用单点或不同内存单位混算 | | macOS兼容 | 至少macOS13 Intel与设备B macOS27 arm64的目标覆盖;多屏/缩放/Spaces/全屏测试;支持范围和未验证版本明确 | 最终包commit/SHA/架构/签名/系统/应用版本矩阵;目标必测项不得SKIP冒充通过 | | 隐私安全与数据 | 核心零网络/遥测、唯一配置、合规数据;测试与异常路径保护已有数据 | make verify零诊断、安全脚本正常/失败/中断证据,独立第三方离线重建及零外联核验 | | 分发就绪 | 签名、公证、Gatekeeper、二进制/源码对应、附件摘要、安装/升级/卸载恢复及发布说明齐全 | 锁最终提交与候选;实机安装和第三方核验;同页长期源码交付;发布操作单独记录 | diff --git a/docs/reviews/265-p1u-followup-latency-memory.md b/docs/reviews/265-p1u-followup-latency-memory.md index b137eea..8acdd50 100644 --- a/docs/reviews/265-p1u-followup-latency-memory.md +++ b/docs/reviews/265-p1u-followup-latency-memory.md @@ -2,7 +2,8 @@ - 日期:2026-11-12 / Claude Code(air 本机) - 范围:报告 264 之后的收尾——仓库状态核对、把探针测不了的项尽量补上、延迟与内存门禁复测 -- 结论:**延迟 PASS(稳态 p95 7.33 ms,0 外联);内存门禁在学习区开启时不稳定——新旧包 A/B 显示稳态无回归,但两者都贴着 34 MiB 门槛**(§4.1)。 +- 结论:**延迟 PASS(稳态 p95 7.33 ms,0 外联);内存无回归——重启后新旧包同条件各 5 轮完全一致(§4.3),但门禁口径本身失效: + 已发布的 1.2.1 在干净系统上同样 5 轮全超 34 MiB,而存活堆只有约 20 MiB**。 新包「首键」时点高约 4.6 MiB 已归因(§4.2):**不是泄漏、也不是数据变多**,是采样时是否恰好有一个输入会话存活;稳态存活堆新包多约 0.5 MiB。 ## 1. 仓库状态(核对时) @@ -118,6 +119,33 @@ A/B 过程中的换包:旧包与新包各经 `install.sh` 覆盖安装一次 这很可能就是冷首键 30 ms 量级延迟(ADR-307)的主要来源,且与本批改动无关。是否改成「宿主存活期间常驻数据」是内存换延迟的取舍, 需单独立 ADR(会让无会话时的常驻内存从约 5 MiB 升到约 20 MiB)。 +### 4.3 重启后重测(2026-11-12 夜,用户重启电脑后) + +条件:开机后等 1 分钟负载降到 4 以下再开始;全程 **swap 用量 0**,负载 1.3–3.7。同一配置(学习区开,门槛 34 MiB),各 5 轮,新 → 旧 → 装回新。 + +| 包 | 时点 | 「私有已提交」逐轮 | 中位数 | 存活堆 | 判定 | +|---|---|---|---|---|---| +| 新 `f38e4e1a…` | six-words | 35.0 / 37.5 / 37.2 / 37.4 / 37.6 | **37.4** | 20.1–20.2 | FAIL | +| 新 | idle-8s | 34.9 / 37.3 / 37.0 / 37.3 / 37.5 | **37.3** | 20.1 | | +| 新 | first-key | 33.2 / 34.1 / 33.0 / 32.7 / 34.4 | 33.2 | 19.2 / 5.1 ×4 | | +| 旧 `3eeeb0aa…`(1.2.1 发布版) | six-words | 37.3 / 37.5 / 37.5 / 37.3 / 37.7 | **37.5** | 20.2 | FAIL | +| 旧 | idle-8s | 37.2 / 37.3 / 37.3 / 37.2 / 37.5 | **37.3** | 20.1 | | +| 旧 | first-key | 33.0 / 33.1 / 32.4 / 33.3 / 34.1 | 33.1 | 5.1 ×5 | | + +结论: + +1. **新旧包没有差别**:稳态中位数 37.4 对 37.5、37.3 对 37.3,存活堆都是 20.1–20.2 MiB,首键时点也一致。§4.1 里看到的差异全部是测量噪声。 + 本批改动(ADR-325…336)**没有内存回归**。§4.2 说的「稳态存活堆 +0.5 MiB」在干净状态下也不成立(那是用户词库与系统状态的差异)。 +2. **已发布的 1.2.1 在干净系统上同样过不了这道门禁**(5 轮全超,约 37.3–37.7 对 34)。门槛失效与本批无关。 +3. **「私有已提交」这个口径随系统内存压力反向变化**:swap 用满时 31–34 MiB,swap 为 0 时 35–37.6 MiB,而存活堆始终约 20 MiB。 + 差出来的 13–17 MiB 是分配器已释放但系统尚未回收的页——内存紧张时被回收(数字变低),内存宽裕时留着(数字变高)。 + 它量的主要是系统状态,不适合做有固定门槛的门禁。首键时点最能说明问题:存活堆只有 5.1 MiB,这个口径却报 33 MiB。 + +**已落地(ADR-338,2026-11-13)**:门禁判定口径改为 `heap_live_mb`,门槛 24 MiB,不再按学习区分档;「私有已提交」与 footprint 降为参考项。 +用 `ANALYZE_ONLY=1` 对本报告的 5 组快照(共 23 轮)重新判定:全部 PASS,稳态存活堆 20.1–21.2 MiB。 + +结束状态:已装回新包 `f38e4e1a…`(`3e428b7`),宿主跑新二进制,输入源为萤火虫。证据:`50-mem-reboot-*.txt`、`51-mem-reboot-*.txt`、`memory-reboot-new/`、`memory-reboot-old/`。 + ## 5. 仍未验证 `12:30`、五笔码浮层是否可见、练习「字根」「词组」题型、设置页 7 个新开关、DMG 安装完成页——都需人工目视。 diff --git a/docs/reviews/README.md b/docs/reviews/README.md index 5ec9e1e..cbb9c40 100644 --- a/docs/reviews/README.md +++ b/docs/reviews/README.md @@ -39,7 +39,7 @@ | 1.1.0 发布线 | 225–250 | 简码/排序、验收成本、延迟归因、1.1.0 发布与站点 | | 1.2.0 候选与发布 | 251–262 | B1 门禁、B0 运行时、学习区、练习四题型与键位图、1.2.0 发布 | | 1.2.1 清理 | 263 | 安装/无障碍补丁、死代码与文档审计 | -| P1-U 补充复验 | 265 | 分号选词真机 PASS;延迟稳态 p95 7.33 ms PASS;内存 A/B:稳态无回归但学习区开启时贴 34 MiB 门槛;首键 +4.6 MiB 归因为采样时会话是否存活(非泄漏),稳态存活堆 +0.5 MiB | +| P1-U 补充复验 | 265 | 分号选词真机 PASS;延迟稳态 p95 7.33 ms PASS;内存:重启后新旧包各 5 轮完全一致、无回归;门禁口径失效(1.2.1 发布版在干净系统上同样全超 34 MiB,存活堆约 20 MiB) | | P1-U 装机 | 264 | ADR-324…336 候选 `3e428b7` 装机 PASS;真机键入复验 22/22 PASS(首轮因无辅助功能权限 BLOCKED,授权后复跑);5 类目视项待人工 | ## 4. 常见查找 diff --git "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" index befd526..e426acd 100644 --- "a/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" +++ "b/docs/\345\206\263\347\255\226\350\256\260\345\275\225.md" @@ -3432,3 +3432,31 @@ `make verify`、离线回归、预览冒烟、`build.sh --strict` 全绿。**两项修复都待换包后实机确认。** - **状态**:已采纳(2026-11-12)。 - **关联**:ADR-325、ADR-331、ADR-335、报告 264/265。 + +### ADR-338:常驻内存门禁改以「存活堆」判定,门槛 24 MiB + +- **背景**:`memory-gate.sh` 此前以「私有已提交」(vmmap 的 Writable regions resident + swapped_out)判定,门槛 30 MiB、学习区开启时 34 MiB + (ADR-263/292/312)。报告 265 的三轮实测表明这个口径不可用: + - 同一份包,swap 用满时稳态 31–34 MiB,重启后 swap 为 0 时 35–37.6 MiB——**随系统内存压力反向变化**; + - 已发布的 1.2.1 在干净系统上 5 轮全部超过 34 MiB; + - 首键时点存活堆只有 5.1 MiB,该口径却报 33 MiB。多出的是分配器已释放、系统尚未回收的页。 + - 而存活堆在全部条件下稳定:新旧包、重启前后共 23 轮,稳态 20.1–21.2 MiB。 +- **决策**: + 1. 判定口径改为**稳态时点的存活堆**:`vmmap -summary` 的 MALLOC ZONE 表里 `DefaultMallocZone` 的已分配字节(`heap_live_mb`)。 + 2. 门槛 **24 MiB**,**不再按学习区开关分档**(实测约 20–21 MiB,余量约 3 MiB / 15%)。`LIMIT_MB` 仍可由调用方覆盖。 + 3. 「私有已提交」与 physical footprint 继续采样、写入 JSON,但**只作参考**,不参与判定。 + 4. 读不到存活堆(vmmap 输出格式变化)按 **FAIL** 处理,不退回旧口径。 + 5. 新增 `ANALYZE_ONLY=1`:只对已有快照目录重新判定,不重启宿主、不发键——用于复核旧证据与验证脚本改动。 +- **取代关系**:本条取代 ADR-263/292 的判定口径与 ADR-312 的两档门槛;那三条的测量方法与历史数字保留作背景,不改写。 + 对用户的承诺由「常驻内存 ≤30 MB」改述为「输入法自身持有的数据约 20 MiB,门禁 24 MiB」; + 系统「活动监视器」里看到的数字含共享库与可回收页,会更高,且随系统状态变化。 +- **理由**:门禁要回答的是「这次改动有没有让输入法多占内存」,只有不随系统状态漂移的量才能设固定门槛。 + 存活堆直接对应码表、拼音表、用户词库与候选对象的大小,新增数据或泄漏都会如实反映。 +- **边界 / 已知限制**: + - 存活堆不含映射文件与代码段;若将来改用 mmap 加载词典,需要把映射的常驻页另算进门禁。 + - 学习区**关闭**时的存活堆没有单独实测(用户配置为开启);预期不高于开启时,门槛同为 24 MiB。 + - 只统计 `DefaultMallocZone`;宿主若出现大额的其它 zone 分配不会被计入(当前其它 zone 合计不足 1 MiB)。 +- **验收**:用 `ANALYZE_ONLY=1` 对报告 265 的 5 组快照(新旧包 × 重启前后,共 23 轮)重新判定,全部 PASS,稳态存活堆 20.1–21.2 MiB; + `test-acceptance-tooling.py`、`test-probe-cleanup.py` 与离线回归全绿。 +- **状态**:已采纳(2026-11-13,用户指示「先定内存口径」)。 +- **关联**:ADR-263、ADR-292、ADR-312、报告 198/209/256/265。 diff --git "a/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" "b/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" index 5ad60ad..22c5dfe 100644 --- "a/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" +++ "b/docs/\345\276\205\345\212\236\344\270\216\347\247\257\345\216\213.md" @@ -76,6 +76,9 @@ > 拼音上屏后的五笔码浮层、练习「字根」题型。**第二档剩余**:U2-2 五笔造词(要定启发式)、U2-3 扩展词库(要联网取数据并登记许可)、 > U2-5 分阶段解锁与跟打(要定口径与文本来源)——三项都需要你先拍板,不是能直接开工的活。 +> **内存结论(报告 265 §4.3,重启后重测)**:新旧包同条件各 5 轮完全一致,**本批无内存回归**;但门禁口径失效——1.2.1 发布版在干净系统上同样全超 34 MiB,存活堆只有约 20 MiB。 +> **已定(ADR-338)**:门禁改以存活堆 `heap_live_mb` 判定、门槛 24 MiB;用旧快照复核 23 轮全部 PASS(20.1–21.2 MiB)。此前关于「贴线」「首键 +4.6」「稳态 +0.5」的说法以本条为准。 +> > **实机反馈(2026-11-12,ADR-337)**:`12:30` → `12;30`(Shift 标点取字符有误,已修);拼音上屏后五笔码提示不出现(已加固并加诊断,**根因未定位、未确认修好**)。 > 用户已确认练习「字根」「词组」题型正常;内存门槛定为「重启电脑后重测再定」;DMG 完成页待出 DMG 后确认。 > diff --git a/scripts/acceptance-evidence.py b/scripts/acceptance-evidence.py index 3f1f159..5f32402 100755 --- a/scripts/acceptance-evidence.py +++ b/scripts/acceptance-evidence.py @@ -28,7 +28,7 @@ "hotkeys": ("快捷键", "热键", "shift 切", "⌥p", "⌥f", "⌥t", "⌥m"), "clients": ("客户端", "client matrix", "文本编辑/safari", "safari"), "quality": ("质量样本", "quality-samples"), - "memory": ("内存门禁", "memory-gate", "adr-263", "adr-292"), + "memory": ("内存门禁", "memory-gate", "adr-263", "adr-292", "adr-338"), "soak": ("久用", "soak"), "network": ("零外联", "外联", "tcp/udp", "0 条"), "voiceover": ("voiceover", "播报", "axannouncementrequested"), diff --git a/tools/macos-probe/memory-gate.sh b/tools/macos-probe/memory-gate.sh index 99ba170..59c0e4c 100755 --- a/tools/macos-probe/memory-gate.sh +++ b/tools/macos-probe/memory-gate.sh @@ -1,24 +1,23 @@ #!/bin/sh -# ADR-263/292「常驻内存 ≤30MB」口径复测:新启动宿主 → marker 先行 → 四个固定时点采样 → 至少 3 个独立轮次。 -# 判定:稳态时点的「私有已提交」(Writable regions resident + swapped_out)≤ LIMIT_MB —— 这是进程自己持有的量。 -# footprint 仍然采样并打印,但只作参考:它含共享只读库页,随 macOS 版本变化(报告209:同一份 0.1.13 与 0.1.14 -# 在 macOS 27 上 footprint 29–34M、私有 26–29M;在 macOS 13 上 footprint 20.6–20.9M),跨版本不可比。 -# 注意:这也不是探针 RSS 口径(报告198)。 -# 用法:memory-gate.sh [ROUNDS=3];输出 JSON 摘要 + 每轮 vmmap 全文到 OUT。 +# 常驻内存门禁(ADR-338):新启动宿主 → marker 先行 → 四个固定时点采样 → 至少 3 个独立轮次。 +# 判定:稳态时点的**存活堆**(vmmap 的 MALLOC ZONE 表里 DefaultMallocZone 的已分配字节)≤ LIMIT_MB(默认 24 MiB)。 +# 这是进程此刻真正持有的数据量,不随系统内存压力变化。 +# 「私有已提交」(Writable regions resident + swapped_out)与 footprint 仍然采样并打印,但**只作参考**: +# 它们含分配器已释放、系统尚未回收的页,swap 用满时偏低、swap 为空时偏高(报告265 §4.3:同一份包 31–34 对 35–37.6 MiB), +# footprint 还含共享只读库页、随 macOS 版本变化(报告209)。两者都不是探针 RSS 口径(报告198)。 +# 用法:ROUNDS=3 memory-gate.sh;输出 JSON 摘要 + 每轮 vmmap 全文到 OUT。 +# ANALYZE_ONLY=1 OUT=<已有目录> ROUNDS=<轮数> memory-gate.sh 只对已有快照重新判定,不重启宿主、不发键。 set -u PROBE="$(cd "$(dirname "$0")" && pwd)" BIN="$PROBE/bin" SOURCE="${SOURCE:-cn.jokerhub.inputmethod.Lampyris.default}" ROUNDS="${ROUNDS:-3}" -# ADR-312:默认配置(学习区关闭)守 30 MiB;学习区开启时放宽到 34 MiB(实测稳定差约 3 MiB,报告 256)。 -CALLER_LIMIT_MB="${LIMIT_MB:-}" -LIMIT_MB="${LIMIT_MB:-30}" +# ADR-338:存活堆实测约 20–21 MiB(学习区开启、新旧包一致),门槛 24 MiB,不再按学习区开关分档。 +LIMIT_MB="${LIMIT_MB:-24}" +ANALYZE_ONLY="${ANALYZE_ONLY:-0}" OUT="${OUT:-/tmp/lampyris-memory-gate-$(date -u +%Y%m%dT%H%M%SZ)}" SUPPORT="${SUPPORT:-$HOME/Library/Application Support/Lampyris}" APP="$HOME/Library/Input Methods/Lampyris.app" -if [ -z "$CALLER_LIMIT_MB" ] && grep -qE '^show_wubi_learning[[:space:]]*=[[:space:]]*true' "$SUPPORT/config.toml" 2>/dev/null; then - LIMIT_MB=34 -fi mkdir -p "$OUT" host_pid() { pgrep -x Lampyris | head -1; } @@ -38,6 +37,7 @@ restart_host() { type_keys() { "$PROBE/type-session.sh" "$1" --settle 2 >/dev/null 2>&1; } ROUND=1 +[ "$ANALYZE_ONLY" = "1" ] && ROUND=$((ROUNDS + 1)) while [ "$ROUND" -le "$ROUNDS" ]; do restart_host sleep 2 @@ -52,7 +52,7 @@ while [ "$ROUND" -le "$ROUNDS" ]; do { date -u +%FT%TZ; uptime; vm_stat | head -1; sysctl -n vm.swapusage; } > "$OUT/round-$ROUND-env.txt" ROUND=$((ROUND + 1)) done -"$BIN/tissrc" select com.apple.keylayout.ABC >/dev/null 2>&1 +[ "$ANALYZE_ONLY" = "1" ] || "$BIN/tissrc" select com.apple.keylayout.ABC >/dev/null 2>&1 python3 - "$OUT" "$ROUNDS" "$LIMIT_MB" "$(shasum -a 256 "$APP/Contents/MacOS/Lampyris" | awk '{print $1}')" \ "$(shasum -a 256 "$SUPPORT/config.toml" 2>/dev/null | awk '{print $1}')" <<'PY' @@ -76,8 +76,7 @@ def parse(path): if not footprint or not writable: return None resident, swapped = to_mb(writable.group(1)), to_mb(writable.group(2)) - # 报告265:「私有已提交」含分配器已释放但未归还的页,受采样时机影响很大; - # 同时记下 MALLOC ZONE 表里的存活分配(字节与个数),用来区分「数据真变多了」与「分配器残留」。只作参考,不参与判定。 + # ADR-338:判定用 MALLOC ZONE 表里的存活分配(字节);「私有已提交」含分配器已释放但未归还的页,只作参考。 zone = re.search(r"^DefaultMallocZone\S*\s+\S+\s+\S+\s+\S+\s+\S+\s+(\d+)\s+([0-9.]+[KMG]?)", text, re.M) return { "physical_footprint_mb": round(to_mb(footprint.group(1)), 1), @@ -107,12 +106,16 @@ steady = [point for point in POINTS if point in ("six-words", "idle-8s")] for row in results.values(): for point in steady: sample = row.get(point) - if not sample or sample["private_committed_mb"] > limit: + live = sample.get("heap_live_mb") if sample else None + # 读不到存活堆(vmmap 输出格式变了)按失败处理,不退回旧口径——宁可红也不要用一个不可信的数放行。 + if live is None or live > limit: failed = True summary = { "rounds": rounds, "limit_mb": limit, + "metric": "heap_live_mb", "footprint_is_informational": True, + "private_committed_is_informational": True, "steady_points": steady, "exec_sha": exec_sha, "config_sha": config_sha,