iOS 内存压缩器实测报告
WKdm 与 LZ4:混合架构,还是单一压缩器?两压缩器效率差异全景

iPhone 12 Pro Max (A14) · iOS 14.8.1 (18H107) · xnu-7195 · 16KB 页 · Taurine 越狱真机实验 · 2026-09-11
混合架构
XNU 源码设计(iOS 12→18):metacompressor 逐页在 WKdm / LZ4 / MZV·SV / raw 间选择,arm64 默认 HYB 模式
本机单压缩器
三重行为证明:这台 14.8.1 RELEASE 实际只有 WKdm 在干活,LZ4 路径从未产出任何页
−36% 内存
混合负载模拟:媒体/图形类负载 HYB 比纯 WKdm 省 36% 存储空间(App 堆负载省 17%)
一句话结论:iOS 压缩器设计上是多压缩器混合架构(WKdm 主力 + LZ4 兜底 + 单值去重 + 原样存储),但本实验设备运行时实际生效的只有 WKdm 一个压缩器;效率实测表明两者高度正交互补——WKdm 赢在真实堆页面的速度与压缩率,LZ4 赢在结构性重复数据,混合策略在不同负载下比单策略省 17%–36% 内存。

1 · 实验设计:双路证据

路 A · Mac 参考指纹:把 XNU-7195 原始内核汇编(WKdmCompress_16k.slz4_encode_arm64.s)直接链接成参考程序,对 7 种确定性数据模式各 64 样本计算两算法输出指纹——与设备字节级同源(patterns.h 共享)。

路 B · 设备行为探针(cspray v9):喷洒 96MB 特定模式匿名内存 → posix_spawn 双 ballast(2×2.2GB 自适应)把 free 压入回收区间 → 全页被压缩后取快照 A → 全页重读(解压 + fnv1a 校验)取快照 B → PHYS = cusedA − cusedB 即我方页面物理压缩字节。九轮协议迭代解决 COW 记账、窗口污染、file cache 吸收等问题。

路 C · 设备端基准(本篇新增):把同一套内核汇编链接为 iOS 可执行(设备端 ldid 签名),在 A14 上实测 10 种数据形态 × 双 codec 的编解码延迟与输出大小。

2 · 存储指纹:设备行为 vs 三种假设

数据形态WKdm 输出LZ4 输出纯WKdm预测HYB预测*设备实测 perpage判定
zeros 全零页4B (MZV)193BSV 4BSV 4B(环境性未采样)
dict16 指针页7594.5B11488.1B75947594 (<阈值)8448.5 / 8451.4 / 8467.6✓ WKdm(3 次复现,+1KB 槽对齐+~850B 段开销)
random 随机FAILFAILrawraw1.0067(校准轮)raw ✓
ramp251 周期斜坡FAIL441Braw44116305.6 / 16234.8raw copy —— LZ4 兜底未发生!
singleval 单值页4B (MZV)201BSVSV45.5 / 69.5✓ SV 单值路径
dict256 256词字典FAIL13836.4Braw1383616264.7raw copy —— 同上
r3rep1 阈值区构造14289.5B15390.5B1428915390 (≥12288 必换LZ4)14289.0精确 = WKdm 原样存储,未被 LZ4 替换!

* HYB 规则(vm_compressor_algorithms.c):WKdm 先行;失败或输出 ≥ 12288B(16KB 页的 75%)→ 改试 LZ4 且无条件存储;LZ4 也失败 → 16KB 原样副本。

终审实验:阈值翻转无响应

sysctl -w vm.lz4_threshold=1(HYB 下每页成功压缩都会 ≥1,应全部转投 LZ4 存储):

条件HYB 预测 P1 perpage实测结论
threshold = 12288(默认)8448(WKdm 7594 < 阈值,存 WKdm)8448.5
threshold = 1~12400(全部转 LZ4@11488+开销)8451.4(Δ<0.3%)HYB 分支从未执行
三重独立证明收敛:① P6 精确命中 WKdm 输出 14289(HYB 下不存在存该值的代码路径);② 阈值 12288→1 零响应;③ WKdm 失败页(P3/P5)直接 raw copy 无 LZ4 兜底。⟹ vm_compressor_current_codec ≠ CMODE_HYB,本机实际以纯 WKdm 模式运行(CMODE_WK 或 legacy 默认路径,二者行为不可区分)。boot-args 为空已排除启动参数覆盖;开源源码 arm64 默认是 HYB —— 差异在 Apple 内部构建配置。

3 · 效率实测:A14 上双压缩器 10 形态基准

同一套 XNU 内核汇编(与真机内核同源),iPhone 12 Pro Max 单线程用户态,64 页 × 7 遍取中位,全部往返校验通过。时间单位 µs/16KB页。

数据形态WKdm 编码WKdm 解码WKdm 输出LZ4 编码LZ4 解码LZ4 输出胜负
zeros 全零3.580.67*4B MZV2.6045.08193BWKdm 48× 小
singleval 单值8.210.67*4B MZV2.6131.21201BWKdm 50× 小
dict16 指针页31.2923.137594.5B56.4025.6711488.1BWKdm 快1.8× 且小1.5×
heap50 半满堆31.1626.878628.6B59.6118.4110555.1BWKdm 快1.9× 且小1.2×
r3rep1 阈值区13.649.2014289.5B40.625.4715390.5B各擅一场
ramp251 周期斜坡1.18FAIL3.161.02441.0BLZ4 独赢 37×
dict256 256词字典13.17FAIL69.0613.3213836.4BLZ4 独赢
text ASCII词汤7.34FAIL67.0814.7310434.3BLZ4 独赢
ptr300 指针池8.98FAIL69.6712.5314080.6BLZ4 独赢
random 纯随机1.17FAIL35.13FAILraw copy(memcpy 0.79µs)

* MZV 广播解码(SV 路径,4B 槽位广播 16KB),非真实解码。FAIL = 超出 16380B 预算放弃。memcpy 16KB = 0.79µs(20.7 GB/s)。

1.8–3×
可压缩页上 WKdm 编码全面快于 LZ4(dict16: 524 vs 291 MB/s)
30×
WKdm 失败检测成本(1.2–13µs 快速认输)vs LZ4 扫完全页(35–70µs)——混合策略的兜底代价极低
0.67µs
MZV 广播解码(24 GB/s)——零页/单值页近乎零成本,本机 perpage 45B 实测下界印证
1.5–1.7×
匹配密集页上 LZ4 解码反而更快(长匹配 memcpy 王道),但编码要付 8KB 哈希表清零

4 · 混合负载模拟:三种策略对决

用第 3 节实测数据按内存构成加权,模拟三种真实负载下「纯 WKdm / 纯 LZ4 / HYB 混合」的存储成本与编解码开销:

负载构成策略存储 B/页压缩率编码 µs/页解码 µs/页内存节省**
A · App 日常堆
28%零+25%半满堆+15%指针+…
纯 WKdm81500.49716.010.9基准
纯 LZ479030.48240.224.73.0%
HYB 混合67810.41432.113.316.8%
B · 媒体/图形
25%周期瓦片+20%纹理+15%色表+…
纯 WKdm142540.8706.72.5基准
纯 LZ492310.56337.110.835.2%
HYB 混合91150.55640.66.836.0%
C · 计算/数据
40%随机+25%周期+15%半满堆+…
纯 WKdm135230.8259.16.9基准
纯 LZ499270.60632.98.926.6%
HYB 混合92400.56427.37.731.7%

** 相对同负载下最差策略的存储字节。HYB 按内核真实规则模拟(WKdm 先行,失败或 ≥12288B 转 LZ4 无条件存储,MZV→SV,双失败→raw)。

这就是「分别在不同场景使用」的量化答案:App 日常堆(指针/零为主)WKdm 已经拿走大部分收益,HYB 再省 17%;而结构重复占比高的媒体/图形与计算负载,纯 WKdm 几乎失效(0.83–0.87),HYB 的 LZ4 兜底带来 32–36% 的存储节省——代价只是每页多付 1–13µs 的 WKdm 快速失败检测。HYB 在三种负载下解码都优于纯 LZ4(MZV/raw 页走广播/memcpy)。

5 · 为什么 WKdm 是主角:正交互补

WKdm 利用词级值统计:32 位词打标签(零词 2bit / 字典命中 4bit / 新词 32bit),16 槽滚动字典。真实内存页的冗余恰好在词级——零填充、重复指针、小整数簇。它是 90 年代 IBM 专为内核换页压缩设计的:固定成本、无跨页状态、超预算立即放弃、最坏情况可证明——这正是持锁内核回收路径最看重的性质。

LZ4 利用字节级位置回溯(LZ77 窗口):不管值统计,只要结构重复就能抓到。ramp251(周期 251B 的计数器/瓦片型数据)压到 0.027,dict256(色表型)压到 0.844——这两类 WKdm 全部放弃。

两者失败集合几乎不相交:dict16 词冗余高但顺序乱(LZ4 找不到长匹配 11488B vs WKdm 7594B),ramp251 词冗余低但结构强重复(WKdm FAIL vs LZ4 441B)。这正是 HYB 设计的逻辑:WKdm 先筛(便宜且覆盖主形态),硬页换机制再试(LZ4 兜底),都失败才付 16KB 存储成本。此外内核还有负载级自适应预选器(compressor_preselect,LZ4 连胜→跳过 WKdm / 连败→永久跳过 LZ4),iOS 14 默认休眠,iOS 18 起开放 sysctl 调节。

6 · 版本演化(源码六版本 diff)

版本arch变化
iOS 12 (4903) / iOS 13 (6153)arm64相同:HYB 默认,lz4_threshold=2048
iOS 14 (7195)arm64+popcount 快速检测;16K 页时 threshold 补丁为 12288;本机行为=纯 WKdm(构建配置差异)
iOS 15 (8792)arm64+__ARM_16K_PG__ 条件编译;metacompressor 与 7195 逐字相同
iOS 18 (11215)arm64tuneables 改为 sysctl 可变(运行时可调 codec/threshold)

7 · 意外发现与工程坑(真机实验全记录)

① 内核 panic 复现:极限内存压力(free<500 页)触发 "226165 is locked down (0x6800000000000000), cannot remove" 内核崩溃(panic-full-2026-09-11-114535.ips 已归档)。后续实验必须设 free 地板(≥1400 页)。

② 压缩器惰性:file cache 未耗尽前(可回收池 1–3.5GB 随机波动)压缩器完全静止——dCin 逐秒冻结是最可靠的「没在工作」判据。矩阵实验必须带重试。

③ task_for_pid 分级:pid>0(含 launchd)✓;pid=0(内核端口)✗ 0x5——四项 entitlement 齐全仍被拒,内核内存直读不可行,本报告靠行为实验替代。

④ 设备端签名是唯一解:Mac 侧 ldid 签名一律 SIGKILL(137);上传未签名二进制后设备端 /usr/bin/ldid -S/tmp/ents_full.plist(get-task-allow + task_for_pid-allow + no-container + system-task-ports)才被认可。

⑤ cused 记账只含对齐 payload:per-slot 按 1KB 对齐(WKdm 7594→8192/9216),段级还有 ~850B/页固定开销——把设备 perpage 与参考输出直接相减即可校准。

8 · 工具与数据

文件说明
src/cspray.c设备行为探针 v9(快照协议:ballast 协调 + A/B 快照 + fnv1a 校验)
src/bench_codec.c设备端双压缩器基准(本页 §3 数据源,链接 XNU 原始汇编)
src/refcomp.c + patterns.hMac 参考指纹(§2 路A),两端字节级同源
bench/bench_results.json§3/§4 全部原始数据(含混合负载构成定义)
device/*.txt13 个设备运行日志(矩阵两轮 + 协议验证五轮 + 阈值终审)
panic/*.ips内核 panic 日志

全部数据归档于实验机 raw-data/ios-compressor-verify/;XNU 源码锚点见 xnu-source-analysis skill(第十批)。