能正交相加,但必须换分母:用「页状态」做桶 → 各项互斥、严格可加(下面每项都实测闭合到页); 用「进程 footprint」做桶 → 必炸:朴素五维求和 = 5198.7 MiB ≠ 6144 MiB,差 945.3 MiB,五个交叉项已逐一量化(见第四节)。 修正版五维(文件缓存计入可用 + 去两处重复)已做到严格加总 = 6,144.0 —— 见第七节。
hw.memsize = 5735.95 MiB,不是 6 GiB。
物理芯片 6 GiB 要从 ioreg dram-size 读(0x180000000 = 6,442,450,944 B)。第一层 408.05 MiB 固件预切,OS 根本看不见。| 层 / 状态 | 页数 | MiB | 含义与数据源 |
|---|---|---|---|
| 物理 DDR | 393,216 | 6,144.0 | ioreg dram-size = 0x180000000 |
| ├ R_chip(固件预切) | 26,115 | 408.05 | dram-size − hw.memsize(SEP/AOP 等,OS 不可见) |
| └ hw.memsize | 367,101 | 5,735.95 | sysctl hw.memsize(= host_basic.max_mem) |
| ├ W wire | 48,111 | 751.7 | vm_stat「Pages wired down」=内核及驱动主体 |
| ├ F free(立即可用) | 40,425 | 631.6 | 含 speculative 17,536 页(274.0 MiB) |
| ├ active | 92,470 | 1,444.8 | E=ext 138,073(2,157.4)+ N=int 57,137(892.8)= active+inactive+speculative(恒等式③) |
| ├ inactive | 85,204 | 1,331.3 | |
| ├ C 压缩器占用 | 89,968 | 1,405.8 | 槽位;内存放 181,044 stored 页(2,828.8 MiB)数据 |
| ├ T throttled | 0 | 0.0 | vm_stat「Pages throttled」 |
| └ R_pool(页池内预留) | 10,923 | 170.7 | secluded 9,600 页=150 MiB(ioreg kern.secluded_mem_mb,ANE 隔离区)+ 残差 1,323 页 20.7 MiB |
S(speculative 17,536 页)在公式中必须显式扣一次:它物理上在 free 里、归属上又在 E+N 里——双重身份,只许出现一次。
| 维度 | 实测 | 进程数 | 口径与构成 | |
|---|---|---|---|---|
| 生态应用 | 773.6 MiB | 16 | Σ phys_footprint(路径 /var/containers/):bili 277.8 · News 256.1 · WeChat 91.2 · imeituan 64.6… | |
| 系统服务 | 1,936.3 MiB | 277 | Σ phys_footprint(其余全部):SpringBoard 93.6 · backboardd 89.9 · launchd 82.5 · WebKit×4… | |
| 内核及驱动 | ≈1,278 MiB | — | wire 751.7(实测)+ 内核可分页 12.9(实测 N 未归属)+ 压缩器未归属槽位 513.8(按 stored 占比推算) | |
| 预留 | 578.7 MiB | — | R_chip 408.05 + R_pool 170.7(secluded 150 + 残差 20.7) | |
| 可用 | 631.6 MiB | — | free 立即可用(⊇ speculative 274.0);另有文件缓存 2,157.4 属「潜在可回收」未计入 | |
| 朴素五维求和 | 5,198.7 | ≠ 6,144 → 差 945.3 MiB,见下一节 | ||
/System/Library/Frameworks/WebKit.framework/,
被分进「系统服务」桶——生态应用的真实成本被低估。陷阱②:volatile purgeable 驻留页记在 owner 的
volatile 账本(实测 Σ 1,216 页 ≈ vm_stat 1,270 ✓),不在 internal 字段。| # | 交叉项 | 量化实测 | 后果 |
|---|---|---|---|
| ① | 压缩记账换算差 | footprint 按数据 stored 体积记 1,743.7 MiB,物理只占槽位 1,405.8 MiB | 五维 footprint 口径高估 ~338 MiB |
| ② | 共享页双记账(external / resident 字段) | Σ任务 external = 290,724 页 ≈ 2.1× 物理 138,073 页;Σ resident = 5,457 MiB > 6 GiB | 污染 external/resident 字段——所幸 external 不进 footprint;fp 真正的交叠只有 iokit 残差 29.4 MiB(与内核 wired 桶重叠) |
| ③ | 文件缓存盲区 | 2,157.4 MiB 不在任何 footprint 里,但物理在 DDR 里 | 五维覆盖不了这部分 |
| ④ | speculative 双重身份 | 274.0 MiB 既在 free 又在 E+N | 公式里必须 −S 只算一次 |
| ⑤ | NV 账本陷阱 | ledger_purgeable_nonvolatile 13.9 MiB 若加在 internal 之上恰好多出 13.9 | NV 已含在 int/compressed 里——实测 Σint+Σvolatile+内核可分页 = N 精确闭合,无需 NV 项 |
差额精确对账(run4 实测):缺口 945.3 = 文件缓存未计入 +1,883.4 − 压缩换算差 902.9 − iokit/tag 交叠 29.4(余 5.7 为槽位推算的舍入)。加文件缓存是必要条件,但不充分——见第六节演示。
超出的 938.1 恰好就是两处重复记账:压缩换算差 902.9 + iokit/tag 交叠 29.4(余 5.7 舍入)。 所以正确操作是「加文件缓存 + 去两处重复」同时做——做完即得修正版五维(第七节),严格加总 = 6,144.0。
| 「可用」的两种口径 | 数值 | 说明 |
|---|---|---|
| 立即可用(free) | 631.6 MiB | 分配器直接拿,零成本(内含 speculative 274.0) |
| 宽口径可用(free + 文件缓存 E−S) | 2,515.0 MiB | 合理口径,但回收有代价:文件页清掉后重用需重新 IO;active 里的文件页要先老化 |
| 行 | MiB | 口径与构成(实测 run4) |
|---|---|---|
| 生态应用 | 773.6 | Σ fp(APP),正常算(其压缩数据按 stored 原始体积含在 fp 内) |
| 系统服务 | 1,936.3 | Σ fp(SYS),正常算 |
| 内核及驱动 | 1,798.5 | wire 751.7 + 内核可分页 12.9 + 内核压缩数据(stored) 1,033.9(= comp_stored − Σ任务压缩,实测减法)——不加 comp_occ |
| 预留 | 578.7 | R_chip 408.05 + R_pool 170.7 |
| 可用(立即) | 631.6 | free(⊇ speculative 274.0) |
| 文件缓存(可回收,可并入可用) | 1,883.4 | E − S |
| 压缩节省行 | −1,423.0 | −(comp_stored − comp_occ):实际从总 fp 优化掉的量,整机一条 |
| fp 卫生小项 | −35.0 | −iokit/tag 残差 40.1(与 wire 重叠)+ volatile 19.0(fp 不含)− NV 13.9(fp 内重复) |
| 合计 | 6,144.1 | ≈ 6,144.0 = 6 GiB ✓(0.1 舍入) |
闭合校验:基数里的压缩数据(stored) = 任务侧 1,794.9(在 fp 内)+ 内核侧 1,033.9(内核行)= comp_stored 2,828.8 ✓ → 节省行把整机 stored 一次换算成 comp_occ 口径(2,828.8 − 1,405.8 = 1,423.0)。
历史口径(均与本题恒等于 6,144.0,仅桶间分布不同):整机零假设版(生态 75.9 / 系统 804.0 / 内核含压缩器 2,170.4)与归属视图版(421.8 / 1,350.0 / 1,278.4),详见 REPORT §10.39b/c。
| # | 规则 | 原因 |
|---|---|---|
| 1 | 主干求和只用页状态 | 内核给每页恰一个状态,天然去重,什么都不用扣 |
| 2 | 压缩换算用「节省行」整机一条(−(comp_stored−comp_occ));基数里 stored 必须齐全——任务侧在 fp 内,内核侧走内核行 | stored 是数据体积(2.0×),物理只占槽;基数不齐则减了从未加过的量(差 998.8 实测) |
| 3 | iokit/tag 全归内核桶(唯一归属);NV/volatile 账本不加在 internal 之上 | fp 残差与 wire 重叠;NV 已含在 int/compressed(实测教训 13.9 MiB) |
| 4 | 文件缓存物理单计 E−S;永不用 Σ任务 external / resident_size | spec 已在 free;external/resident 是缺页记账(2.1×) |
验证器(每次普查后跑三条):① Σint+Σvolatile+内核可分页 = N(实测 57,137 精确)② 任务 stored + 内核 stored = comp_stored(基数闭合,本表成立的必要条件)③ 本表合计 = 6,144.0 ± 0.1。
S0 基线 → S1 拉起 B站/微信/抖音/淘宝/小红书 → S2 相机前台(预览管线全开)→ S3 相机后台化+Safari/Maps/照片/音乐 → S4 全家桶+相机再前台(free 仅剩 4,768 页)。同一公式逐场景计算:
| 成分(MiB) | S0 基线 | S1 多应用 | S2 相机 | S3 相机退 | S4 极限 |
|---|---|---|---|---|---|
| 生态应用(fp) | 764.2 | 1,728.0 | 1,739.7 | 1,921.7 | 1,929.9 |
| 系统服务(fp) | 1,935.0 | 2,024.2 | 2,718.3 | 2,360.3 | 2,874.4 |
| ·wire | 745.8 | 794.4 | 1,778.2 | 819.6 | 1,785.0 |
| ·内核可分页 | 4.2 | 133.8 | 81.4 | 245.0 | 62.8 |
| ·内核压缩 stored | 1,074.0 | 1,078.7 | 1,277.3 | 1,061.7 | 1,367.6 |
| 预留 | 586.5 | 566.3 | 560.1 | 564.2 | 555.3 |
| 可用(free) | 626.0 | 214.5 | 99.0 | 317.3 | 74.5 |
| 文件缓存(E−S) | 1,886.8 | 1,255.7 | 720.7 | 921.5 | 698.0 |
| 压缩节省行 −(comp_stored−comp_occ) | −1,407.6 | −1,492.4 | −2,033.9 | −1,817.8 | −2,442.4 |
| fp 卫生小项 | −70.9 | −158.9 | −796.8 | −249.5 | −761.1 |
| 合计(目标 6,144.0) | 6,144.0 | 6,144.0 | 6,144.0 | 6,144.0 | 6,144.0 |
| 偏差 | 0.0 ✓ | 0.0 ✓ | 0.0 ✓ | 0.0 ✓ | 0.0 ✓ |
五个极端状态(free 40,067→4,768 页、wire 47,731→114,242 页、压缩槽 90,070→144,920 页)下合计恒 = 6,144.0,偏差 0.0——公式有效性验证通过。
占用分析 ①:相机的内存签名(S1→S2)
| 相机链组件 | S1 | S2(相机前台) | Δ |
|---|---|---|---|
| wire(ISP/GPU/IOSurface 锁页) | 794.4 | 1,778.2 | +983.8 |
| mediaserverd(采集管线) | 38.4 | 708.4 | +670.0 |
| Camera app 自身 fp | — | 23.9 | +23.9 |
| 文件缓存(被征用供给) | 1,255.7 | 720.7 | −535.0 |
| volatile purgeable 页 | 2,210 页 | 8 页 | ≈清空 |
相机前台总成本 ~2.2 GiB,但 Camera app 自身 fp 仅 23.9 MiB——成本住在 wire(锁页缓冲)与 mediaserverd;S3 相机退场时 wire 回落 −958.6、mediaserverd 708.4→48.6,完全可逆。
占用分析 ②:后台生态 App 的压缩收容(S1 前台新拉 → S4 后台,fp / 驻留 / 压缩 MiB)
| 应用 | S1 fp | S1 驻留 | S1 压缩 | S4 fp | S4 驻留 | S4 压缩 |
|---|---|---|---|---|---|---|
| 抖音 Aweme | 564.6 | 345.5 | 154.8 | 573.1 | 0.5 | 507.7 |
| 淘宝 Taobao4iPhone | 315.0 | 209.5 | 97.2 | 318.3 | 0.5 | 306.9 |
| 小红书 discover | 170.2 | 170.2 | 0.8 | 177.5 | 19.8 | 156.5 |
| Maps / Music(S3 新入) | — | — | — | 106.8 / 46.5 | 16.8 / 40.7 | 69.0 / 4.6 |
铁证:后台化后驻留清零、数据全进压缩器(抖音 345.5→0.5 驻留),而 fp 几乎不变(564.6→573.1)——fp 是配额视角(stored 口径),物理成本全部转移到压缩槽。这正是「压缩节省行」必须存在的实证:节省行 S0→S4 从 −1,407.6 加深到 −2,442.4(节省了 2.4 GiB),压缩器用 2,264 MiB 槽位装下了 4,707 MiB 数据。
| host_statistics64 原子快照 | |
|---|---|
| free / speculative | 40,425 / 17,536 页 |
| active / inactive | 92,470 / 85,204 页 |
| wired / throttled | 48,111 / 0 页 |
| purgeable(volatile) | 1,270 页 |
| ext / int | 138,073 / 57,137 页 |
| comp_occ / comp_stored | 89,968 / 181,044 页 |
| 进程普查(KERN_PROC_ALL) | |
|---|---|
| APP(16)/ SYS(277) | 773.6 / 1,936.3 MiB fp |
| Σtask internal / 全局 int | 55,097 / 57,137 页 |
| 未归属 internal(≈内核可分页) | 824 页(12.9 MiB) |
| Σtask compressed(stored)+tag | 114,874 页 |
| 未归属 stored → 槽位推算 | 32,883 页(513.8 MiB) |
| Σtask volatile 账本 | 1,216 页 |
| TOP 进程(footprint) | MiB | 桶 | TOP 进程(footprint) | MiB | 桶 |
|---|---|---|---|---|---|
| bili-universal | 277.8 | 生态 | 91.2 | 生态 | |
| News | 256.1 | 生态 | backboardd | 89.9 | 系统 |
| SpringBoard | 93.6 | 系统 | launchd | 82.5 | 系统 |
# ① 三层数字 sysctl hw.memsize hw.pagesize vm_stat # 各页状态 ioreg -p IODeviceTree -l | grep -E "dram-size|secluded" # 6GiB 物理与 secluded # ② 全进程普查(探针 ios-probe/cli/memcensus.c,编译后设备侧 ldid 签名) xcrun -sdk iphoneos clang -arch arm64 -o memcensus memcensus.c # 部署后: /var/mobile/ios_memslice/memcensus # 输出 M/V/E/K/S 行 + 每进程 P 行(fp/internal/external/compressed/账本) # ③ 恒等式核验(本页所有 ✓) # states+R_pool==hw.memsize/16384 ; R_chip+memsize==dram-size # ext+int==active+inactive+speculative
proc_listallpids() 在 iOS 只返回 73/295 子集——必须用
sysctl KERN_PROC_ALL,否则系统服务桶低估 5 倍;② task_for_pid(0) 恒拒
kr=0x5(四项 entitlements 也不行),内核桶只能减法+推算;③ 共享文件页被每任务重复记 external 账本,物理求和勿用 Σtask ext。