能正交相加,但必须换分母:用「页状态」做桶 → 各项互斥、严格可加(下面每项都实测闭合到页); 用「进程 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 卫生 ① −iokit 残差 | −29.5 | IOSurface/GPU 缓冲记在进程 fp 又占 wire → 双计,从 fp 侧扣、归内核桶 |
| fp 卫生 ② +volatile 驻留 | +19.0 | volatile purgeable 驻留页 fp 不含(对系统白送),物理在 N 桶 → 补回 |
| fp 卫生 ③ −NV 账本 | −13.9 | ledger_purgeable_nonvolatile 与 internal/compressed 重复(实测加上恰好多出 13.9) |
| fp 卫生 ④ −tagfp | −10.7 | tagged 账本(media/graphics/network/neural)footprint 与内核侧交叠 → 扣 |
| 合计 | 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)。
汇总视图(同项重排,与明细表恒等):可用 = free+文件缓存+volatile 驻留;内核净 = 内核 − iokit 残差;NV+tagfp 合并为 fp 校准项
| 行 | MiB | 构成 |
|---|---|---|
| 生态应用 | 773.6 | Σ fp(APP) |
| 系统服务 | 1,936.3 | Σ fp(SYS) |
| 内核及驱动(净) | 1,769.0 | wire 751.7 + 可分页 12.9 + 内核压缩 stored 1,033.9 − iokit 残差 29.5(任务映射的 IOSurface 锁页改归任务 fp 桶) |
| 预留 | 578.7 | R_chip 408.05 + R_pool 170.7 |
| 可用内存(广义) | 2,534.0 | free 631.6(立即)+ 文件缓存 1,883.4(可回收)+ volatile 驻留 19.0(可丢弃) |
| 压缩节省行 | −1,423.0 | −(comp_stored − comp_occ) |
| fp 校准项 | −24.6 | −NV 账本 13.9 − tagfp 10.7(账本级重复,合并) |
| 合计 | 6,144.0 | 与明细视图恒等(同项重排)✓ |
汇总语义:广义可用 2,534.0 MiB = 全机 41.2%(立即 10.3% + 可回收 30.7% + 可丢弃 0.3%);iokit 残差改记任务侧(mediaserverd 等映射者),内核净桶只剩内核自有内存。
历史口径(均与本题恒等于 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,034.5 | 1,059.5 | 1,252.4 | 1,087.8 | 1,308.4 |
| 预留 | 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 卫生 ① −iokit 残差(相机跟踪项) | −22.0 | −64.8 | −669.4 | −122.1 | −608.5 |
| fp 卫生 ② +volatile 驻留(压力晴雨表) | +20.1 | +15.9 | +0.1 | +27.0 | +9.6 |
| fp 卫生 ③ −NV 账本 | −17.5 | −64.6 | −82.7 | −111.1 | −87.4 |
| fp 卫生 ④ −tagfp | −11.9 | −26.4 | −19.9 | −69.3 | −15.6 |
| 合计(目标 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——公式有效性验证通过。注:场景表初版「内核压缩stored/fp卫生小项」两列因 tagcmp/tagfp 解析键名覆盖各偏 ±(tagcmp−tagfp)(补偿性误差,合计不受影响),已修正。
汇总视图跨场景演化(可用 = free+文件缓存+volatile;内核净 = 内核 − iokit;校准 = −NV−tagfp)
| 行(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 |
| 内核及驱动(净) | 1,762.4 | 1,922.9 | 2,442.6 | 2,030.3 | 2,547.8 |
| 预留 | 586.5 | 566.3 | 560.1 | 564.2 | 555.3 |
| 可用内存(广义) | 2,533.0 | 1,486.1 | 819.8 | 1,265.7 | 782.0 |
| 压缩节省行 | −1,407.6 | −1,492.4 | −2,033.9 | −1,817.8 | −2,442.4 |
| fp 校准项 | −29.4 | −91.0 | −102.6 | −180.4 | −103.0 |
| 合计 | 6,144.0 | 6,144.0 | 6,144.0 | 6,144.0 | 6,144.0 |
广义可用 2,533.0 → 782.0 MiB(41.2% → 12.7%):相机+全家桶把"实际可用"吃到只剩 1/3,其中文件缓存是被主要征用的部分(1,886.8 → 698.0);内核净桶在相机场景涨到 2,442.6——相机锁页缓冲中未映射进任何任务 fp 的部分(≈wire 增量 − iokit 残差增量 ≈ 379 MiB)留在内核,已映射部分(608.5~669.4)归系统服务 fp 桶。
占用分析 ①:相机的内存签名(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,完全可逆。
占用分析 ①补:mediaserverd 的 fp 与 vm_stat 的 wire——重复,不是累加(S5 相机开 ↔ S6 相机关 A/B 实测)
| 量(MiB) | S5 相机开 | S6 相机关 | Δ |
|---|---|---|---|
| mediaserverd fp | 618.8 | 50.7 | −568.1 |
| ·其中 internal(匿名) | 63.3 | 32.8 | −30.5 |
| ·其中 compressed(数据量) | 54.6 | 13.3 | −41.3 |
| ·其中 IOKit 映射(fp−int−cmp−nv,近似含少量 tagged) | 481.4 | 4.5 | −476.9 |
| wire | 1,779.2 | 804.6 | −974.6 |
| N(active+inactive) | 1,571.5 | 1,707.5 | +135.9(Safari 复活) |
| free / comp_occ / E−S | Δ+827.3(含文件缓存回填 +159.7)/ Δ−38.0 / Δ−31.6;状态守恒 ΣΔ ≈ −159 页 ≈ 0(R_pool 微漂移) | ||
判定:IOKit 映射的 476.9 MiB 是内核/驱动分配的相机像素缓冲(IOSurface)映射进 mediaserverd 地址空间——fp 按映射面积记账,vm_stat 按物理持有计入 wire:同一批页,两个账本各记一次 = 重复。若当"累加"处理,相机关闭时应在 N 或 free 出现 ~477 MiB 的"独立缓冲池"——实测没有(N 只涨 Safari 的 135.9,free 的回填与 wire 的跌幅对账 Σ≈0)。wire 跌幅 974.6 = IOKit 映射 476.9 + 内核私有锁页 ~497.7(ISP/驱动 DMA,从不在任何 fp 里)。公式因此必须去重一次:明细视图扣 fp 侧(iokit 残差归内核桶),汇总视图扣内核侧(内核净)。S1↔S2↔S3 早前镜像(mediaserverd fp +670/−660 与 wire +984/−958 锁步)为同一结论的二次印证。
占用分析 ①补2:把"wire 重复量"从 fp 里直读出来(S9 A/B,工具 iokitmap)
| mediaserverd(MiB) | S9 相机开 | S9 相机关 | Δ |
|---|---|---|---|
| fp | 617.3 | 51.4 | −565.9 |
| fp 残差(fp−int−cmp−nv,减法间接) | 474.5 | 4.5 | −470.0 |
| IOSURFACE(88) 区域直读 | 510.2(442 区) | 14.0(2 区) | −496.2 |
| IOKIT(21) 区域直读 | 3.0 | 2.8 | −0.2 |
| wire | 1,781.4 | 795.5 | −985.9 |
内核账本层面这是官方定义 [SRC xnu-7195 task.c:986-1009]:phys_footprint = (internal−alternate_accounting) + (internal_compressed−alternate_accounting_compressed) + iokit_mapped + purgeable_NV(+cmp) + page_table;注释明言 alternate_accounting 是"internal 里属于 IOKit 映射的脏页——同时记在 internal 和 iokit_mapped 两个账本,必须减去避免双计"。但 14.8 的 task_vm_info 不暴露这些字段(task_info.h:388-415,新版 xnu 才有 ledger_alternate_accounting)——所以一行式直读在 14.8 无 API,只能减法。用户态直读走两条路:mach_vm_region_recurse 对 App 可行(抖音 t88=61.6M 与 BSD 路径完全一致),对平台二进制被拒(任务端口转 map 权限门槛,kr=0x4);proc_pidinfo(PROC_PIDREGIONINFO)(BSD 路径,root 即可,不经任务端口)读通平台二进制——mediaserverd 的 IOSURFACE 映射与 fp 残差同步摆动(吻合 92%,差值 ~38 MiB = mediaserverd 的 alternate_accounting/tagged/page_table 记账差)。卫生①今后可直读为主、减法为校验。(注:区域级 pages_resident 对 IOKit 映射对象记账失真,勿用。)
占用分析 ①补3:wire 增量分解——重复 vs 额外驱动开销("是否两组独立页"假设检验)
| Δwire(相机开↔关,S9) | MiB | 在 fp 里吗 | 记账 |
|---|---|---|---|
| mediaserverd 映射的 IOSurface 像素缓冲 | 496.3 | 是(fp 的 iokit_mapped 按映射配额收) | 重复 → 去重一次 |
| 驱动/内核私有(ISP DMA 环、驱动缓冲) | 489.6 | 否(任何 fp 都不含) | 只在 wire,天然无重复 |
| 合计 Δwire | 985.9 | S9 实测 1,781.4 ↔ 795.5 | |
"全部是独立驱动开销"假设被三重反驳:① 状态穷尽——映射的 ~496M DMA 缓冲页必须住在 wire 或 N(不可能是 free/external/compressor);② N 无空间——kp=N−任务账本,相机开时 kp 133.8→81.4 MiB 不升反降(N 的 91% 被任务账本认领),藏不下 496M;③ wire 幅度——全独立且都锁页需涨 985.9+496.3≈1,482M,实测只涨 985.9M。附加强化证据:mediaserverd 自身 pmap 驻留仅 114.7 MiB ≈ int 63.3+ext 46.7——它几乎没 fault 过那 481M 映射(像素由 ISP/GPU 直接 DMA),fp 仍按映射配额收 497M:配额账本与物理账本指向同一批页。误判为"全额外"(不去重)则合计 +496.3 爆表,实测闭合 6,144.0 证明必须去重。
占用分析 ①补4:记账机制——为什么"减法残差"是精确的(求和项里确实有这一项)
[SRC xnu-7195 task.c:1049-1058] 内核给每个任务开一套独立账本列(internal / iokit_mapped / alternate_accounting(+cmp) / page_table / phys_footprint 本身),每列在事件发生时逐次 credit/debit,查询时直接抄表——fp 不是求和算出的,是里程表。[SRC vm_map.c:20208-20229] IOKit 映射进任务时:ledger_credit(iokit_mapped, bytes); ledger_credit(phys_footprint, bytes); 内核注释原话"phys_footprint is a composite limit consisting of iokit + physmem, so we need to bump both counters"——恒等式由构造保证(另有 LEDGER_CHECK_BALANCE 审计、fork 时 vm_map_copy_ledger 整列继承)。但 14.8 的 task_vm_info 只回传部分列(internal/compressed/NV/tagged ✓;iokit_mapped / alternate / page_table ✗,新版 xnu 才暴露)→ 残差 = 未暴露列的打包和,对账本系统精确;"混小项"(page_table 等 ~8%)正是打包的代价。用户态正向 walk 数的是映射区域面积(不同口径,S9 实测差 38.6 MiB),故生产用减法、walk 做交叉验证。
占用分析 ②:后台生态 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。同一套"每页恰一状态、页页闭合、重复记账显式去重"的方法论移植到鸿蒙。数据源全部为单快照可读计数器:
/proc/meminfo + /proc/memview + 每进程 /proc/<pid>/status(VmRSS/RssAnon/VmSwap)
+ /proc/<pid>/smaps_rollup(Pss/Pss_Anon/Pss_File/Pss_HHP)。
A. 物理状态恒等式(空闲态 3 快照验证,残差 ±24 MiB ≈ 0.15%)
MemTotal = MemFree + AnonPages + Cached + Slab + KernelStack + KernelDynamic + PageTables
+ VmallocUsed + ShmmAnon + DireAllocate + ZramUsed + IOFastUsed + IonTotalUsed
+ GpuTotalUsed + DmaHeapThirdTotalUsed + CmaUsed + RsvTotalUsed + Unevictable
+ HhpFree ± ε(±24)
B. 归因拆解公式(iOS 维度 ↔ 鸿蒙计数器,空闲快照实测,MiB)
| 鸿蒙维度 | 计数器口径 | 值 | iOS 对应 |
|---|---|---|---|
| 生态Σ占用(APP) | Σ20个应用(Pss_Anon+Pss_Shmem) | 1,525 | 生态Σfp(APP) |
| 系统Σ占用(SYS) | Σ155个系统进程 同口径 | 1,211 | 系统Σfp(SYS) |
| 匿名归因缺口 | AnonPages−Σ归因 ≈ ShmmAnon(未映射共享页) | 275 | —(iOS fp 无此缺口) |
| 内核 | SUnreclaim+SReclaimable+内核栈+内核动态+页表+vmalloc+DireAllocate | 1,288 | 内核(wire+可分页+内核压缩) |
| 换出DDR占用 | ZramUsed(逻辑换出1,569,节省1,403 → 信息行) | 166 | 内核压缩stored |
| 驱动/图形缓冲池 | IOFastUsed+IonTotalUsed+GpuTotalUsed+三方DMA(空闲态四者互斥) | 1,919 | —(对应物理 wire 里的驱动部分) |
| 预留 | CmaUsed+RsvTotalUsed+HhpFree | 867 | 预留(R_chip+R_pool) |
| Unevictable | Unevictable | 54 | purgeable·NV 邻域 |
| 文件缓存 | Cached | 7,697 | 文件缓存(E−S) |
| free | MemFree | 648 | free |
| 闭合残差 | — | −20 | — |
| 合计 | MemTotal | 15,629.5 | 6,144.0 |
C. 相机 A/B(关→开,与 iOS 相机场景同构的签名)
| 指标 (MiB) | 关 | 开 | Δ |
|---|---|---|---|
| com.huawei.hmos.camera(App 自身 RSS) | 216.5 | 256.6 | +40.1 |
| CameraDaemon(mediaserverd 同构位) | 103.7 | 193.4 | +89.7 |
| camera_service | 17.0 | 29.0 | +12.1 |
| ION/DmaHeap 池(Used) | 507.9 | 2,196.9 | +1,689.0 |
| IOFast 池(Used) | 1,191.9 | 2,737.4 | +1,545.6 |
| ION/DmaHeap 池缓存(可回收部分) | 1,489.4 | 21.9 | −1,467.5 |
| MemAvailable | 7,565.0 | 6,015.0 | −1,550.0 |
| MemFree / Cached / AnonPages | 647.8 | 585.2 | ≈0 |
签名与 iOS 完全同构:相机 App 自身只涨 40 MiB,真实成本 ~1.6-1.7 GB 全在驱动池(ION/DmaHeap +1,689,其中 1,467 来自池缓存转化而非新增 DDR——这正是 MemAvailable 恰好只跌 1,550≈一个池的量的原因;free/文件缓存/匿名纹丝不动)。鸿蒙版"fp×wire 重复"是双账本重复:闭合超额 +3,223 = ① ION×IOFast 同批页两账本各记一次(~1,761,内核自身只把其中一个计入不可回收——MemAvailable 幅度独立证明) + ② 驱动池缓存转化×文件回填(~1,462,IonTotalCache 排空 −1,467 而 Cached 净不变 +5,说明转化页与新写入文件页等量对冲)。公式在相机态需两条卫生行去重,空闲态两者皆 0。
口径注意:① IonTotalUsed−DmaHeapTotalUsed=375.9 恒定(同一池的两个 API 视图);② IOFastTotal==UDrvTotal==DevhostRsvPagesSize≈2.9 GB(设备主机保留区三个名字一个池);③ Pss_HHP(每进程换出归因)存在但其与 ZramUsed/SwapUsed 的精确关系在 1.13 未定,公式 v1 采用"驻留归因+换出整行"的保守口径;④ 相机态闭合超额的分解(1,761/1,462)由池差分推得,颗粒度计数器未暴露。