Skip to content

Memory Contract 技术演进与实验:从单一数字到五指标契约 ​

2026-10-26 · 五指标以外,还要核新来源和参考窗口 ​

本月物理/驻留/虚拟内存历史验收沿用,Free与Available分别取得限定场景五轮证据;这不使五个数字可互换,也不升级为全部系统版本精度保证。

问题表现:值不变时无法仅凭曲线判断是负载稳定还是旧缓存;Free不足以代替Available;参考API读点与产品源窗口不同也会制造“误差”。

实验所得:Free五轮与Available各自场景、组成包络和来源一次发表独立核对。Available的自有host_statistics64组件包络是候选异常对照,secluded完整性与私有字段同义仍未证,不能把包络相容称物理校准。Free阶段验收 · Available方案及结果。原来按更快配置请求不一定得到更快源,曾实测约半秒节拍;配置值不能替代实际窗口统计。源节拍调查。

判断与避免:同一目标生命、完整字段schema、原生时窗和每源唯一发表逐项核;独立读取区间只给上下界,不选中点作真值;参考过宽明确不可评估。进程footprint、resident、virtual与device available/free按scope分开,单位bytes→MiB用2^20,不能把虚拟地址空间的大数解释为实际RAM占用。适用于当前已测设备/版本;旧无标记Session按旧算法回放,不回写新公式。

本节E1复盘,不新增E4;实验方法索引提供跨指标对照步骤。

1. 当前结论先放前面 ​

  • 当前产品内存口径是 memory-contract.v2:五个独立指标(Physical Footprint、Real Memory、Virtual Memory、Available Memory、Free Memory),彼此 scope、语义、证据状态都不同,不能相互替代。
  • 历史上 Xcode Memory 与 Physical Footprint 是同一底层字段 physFootprint 的重复产品命名;Resident Memory 与 Real Memory 是同一底层字段 memResidentSize 的重复产品命名——memory-contract.v2 把这两组重复合并为单一产品指标,旧名只保留兼容语义。
  • 历史上 Available Memory 的公式其实只计算了 vmFreeCount × pageSize(即今天的 Free Memory),并不是 XNU 官方 memorystatus_available_pages 语义;memory-contract.v2 把两者正式分离,新的 Available 是仍处于 candidate 状态的 XNU 语义候选重建。

2. 最初工程问题 ​

早期版本需要快速验证"能否无侵入读取目标 App 内存占用",选择直接透传 sysmontap 返回的若干内存相关字段,并沿用了当时看起来直观的命名(Xcode Memory、Resident Memory、Available Memory)。

3. 第一代方案与为什么当时合理 ​

直接暴露 sysmontap 原始字段并按字面含义命名,是验证链路可用性阶段的合理选择——能最快证明"Perfowl 可以无侵入读到内存数据",不需要等待完整的语义研究。

4. 暴露出的真实问题 ​

  • 同一字段被重复命名为两个"不同"指标:physFootprint 同时被展示为 Xcode Memory 和 Physical Footprint;memResidentSize 同时被展示为 Resident Memory 和 Real Memory。这不是两套独立的采集能力,而是产品层的命名重复,容易让使用者误以为存在两个独立数据源可以相互印证。
  • "Available Memory" 名不副实:旧版把 vmFreeCount × pageSize 命名为 Available Memory,但这个公式只计算了完全空闲页,并不是 XNU 官方语境下"系统认为可以较快投入使用的页面"(还应包含 external/purgeable 等可回收页)。命名与实际语义不符,容易让使用者高估系统真实可用的内存余量。
  • 固定 OOM 阈值缺乏依据:早期文档存在按机型 RAM 大小硬编码 Jetsam 红线的表述,但真实终止阈值受系统版本、设备状态、进程优先级、entitlement 与动态内存压力共同影响,固定数字容易产生误导性结论。

5. 候选方案:memory-contract.v2 五指标拆分(已采纳) ​

  • 假设:把内存语义按"物理占用/驻留映射/地址空间/设备空闲/设备可用"五个不同维度拆开,比维持"内存"这一模糊单数概念更能支撑准确诊断。
  • 方案(FTI-002 开发方案,2026-09-16 批准):
    1. 产品层收敛为五个独立指标,metricID/scope/公式与知识 Canonical 页保持逐项一致;
    2. vmFreeCount × pageSize 正式更名为 Free Memory(ios.device.memory.free);
    3. 新增 Available Memory(ios.device.memory.available)作为 XNU memorystatus 语义的候选重建,公式为 (vmFreeCount + vmExtPageCount + vmPurgeableCount) × pageSize,四项必要字段任一缺失即整体 missing,不退化为 Free 的数值;
    4. 历史 Session 中的 availableMemoryBytes 字段做只读迁移:旧 memoryContractVersion 下按 legacy-free-mislabeled 解释为 Free,不与新 Available 语义混淆,历史文件本身不回改;
    5. 移除固定机型 OOM 红线表述,改为"同设备、同系统、同场景"的相对回归方法论。
  • 判定:采纳,是当前 Registry 与知识库的标准口径。

6. 被证伪路线与停止条件 ​

未发现独立于 memory-contract.v2 方案之外、被系统性实验后又放弃的内存采集路线(不同于 Startup 领域的多次源切换)。当前内存领域的核心工程问题主要是语义澄清与命名纠正,不是采集通道本身的技术路线之争——sysmontap 从项目早期至今一直是内存字段的唯一事实源。

7. 最终方案为什么胜出 ​

五指标拆分方案胜出,原因:

  1. 消除了"两个不同名字实际是同一底层字段"的重复认知负担;
  2. 用准确的命名(Free vs Available)避免了把"完全空闲页"误当作"系统认为可用的全部余量";
  3. 用 fail-closed 的 Available 候选重建(四字段必须同时有效)避免了用不完整数据编造一个看似精确的可用内存数字;
  4. 历史 Session 只读迁移策略保证了新旧口径切换不会静默篡改已发布的历史证据。

8. 从 POC 到产品化又踩了什么坑 ​

  • CORE-8(2026-09-05):新增确定性 RawMetricEngine,五类内存语义在这一批次独立落地(Memory、XcodeMemory candidate alias、Real、Virtual、Available),并明确"没有同场或真机证据的项未升级为数值 validated"。
  • FTI-002 方案(2026-09-16):把知识库、Registry、Collector、Session schema、历史兼容、Export/Report 与 Workbench 统一到同一个版本化契约 memory-contract.v2,并把知识 Canonical 页列为产品代码修改前必须对齐的事实源——公式变化必须先更新知识页,再更新代码与测试。截至当前 devlog 整理,尚未发现该方案对应的独立 result/validation 批次文档;本页据此不对"该契约已完成端到端真机验收"做超出现有证据的断言。

9. 当前仍未关闭的门禁 ​

  • Available Memory 的字段语义验证(尤其 secludedOverTarget 是否可靠取得)与 PerfDog 同窗 E4 校准均未完成,definitionVersion 停留在 candidate.v1。
  • Real Memory 与 PerfDog "Real Memory" 的算法等价性尚未完成同窗 E4 校准。
  • 16 KiB page size 仍是候选架构约束值,不是当前 payload 的设备实测证据。
  • memory-contract.v2 方案本身尚未见到对应的独立真机验收结果批次;现有真机证据依附于跨指标联合采集会话(如 CORE-8 的 E2 产品链验证),不构成契约级的专项 E4 闭环。

10. 可复用工程经验 ​

  1. 发现"同一字段两个名字"时应该合并而不是各自维护:Xcode Memory/Footprint 与 Resident/Real 的重复命名教训说明,产品指标命名前应先确认底层字段是否已有其他名字在用。
  2. 命名要匹配官方语义,而不是匹配"听起来像":把 vmFreeCount × pageSize 叫作 Available 是一个典型的"名不副实"案例,纠正后用更保守但准确的 Free 命名,同时给真正的 Available 语义留出候选重建的空间。
  3. fail-closed 优于凑合输出:Available 的四字段必须同时有效才计算,缺一即 missing,避免了用不完整证据伪造一个看似精确的数字。
  4. 旧数据迁移要保留可追溯的质量标签:历史 availableMemoryBytes 不是简单改名,而是显式标注 legacy-free-mislabeled 迁移语义,保证历史 Session 仍可正确解释。

11. 原始 devlog 索引 ​

  • p2-collector-core-core8-metric-engine.md:五类内存语义的 RawMetricEngine 首次落地。
  • p2-memory-contract-v2-repair-plan.md:memory-contract.v2 完整开发方案(对应内部问题追踪 FTI-002;本方案文档为 approved · E1,尚无独立 result 批次)。

完整正文见 site/devlog/index.md 时间线或对应 /archive/ 归档页。

12. 延伸阅读 ​

版本历史补记 ​

日期修订来源
2026-10-26补本月实验结论、失败路线与适用限制;早期阶段数字保留月度梳理

Perfowl · Performance Observer