ru_minflt 增量与页数在全部 行严格相等(自校验)。vm_pageout_scan 的年龄队列语义一致。vm.lz4_threshold=12288 与源码 arm64/16K 分支设定一致;wk/lz4_compressions 计数器恒 0 由 RELEASE 内核 VMCSTATS 编译屏蔽解释(非未使用)。ru_minflt 增量仍 = 块数 8192 而非 4×8192 —— 若页为 4KB,这 4 次触碰会落入 4 个不同页产生 32768 次缺页;触碰"块内偏移"是免费的 ⇒ 缺页粒度 = 16KB(审计 ID-GRAN-1/2/3)。
② 字节量子整除普查:全部 1568 个 resident / 703 个非零 compressed 内核上报值均为 16384 的整数倍,0 例外(4KB 量子模型下此概率 ≈ (1/4)⁷⁰³;审计 ID-SITE-2)。
③ 守恒恒等式(§5b 真实数据实验,已持久化原始 JSON):realprobe run3 注入真实应用脏页后,子进程 resident 增量 = compressed 减量 = ru_minflt×16384 = 43,859,968 B(2677 页)三方精确相等、majflt=0;appwake 唤醒美团/discover 挂起进程时 compressed 减量 = 解压页数×16384 逐页精确 —— 每次缺页恰好在压缩器与驻留集之间移动一个 16KB 页。(勘误:本节早期版本引用的 7753×16384 数字未持久化原始数据,已被上述可审计数据替代。)
④ 内核二进制指纹:sysctl vm.lz4_threshold=12288 仅在源码 vm_compressor_algorithms.c L447-453 的 PAGE_SIZE==16384 分支被设定(默认 2048)⇒ 运行内核以 16KB 页编译。
⑤ 内核自报四口径一致:hw.pagesize / sysconf(_SC_PAGESIZE) / TASK_VM_INFO.page_size / footprint 工具页注均为 16384。
(诚实说明:微基准里 minflt==页数 这条检查本身不能区分 4K/16K —— 16KB 步长触碰在 4KB 页机器上也每步命中新页;它只验证计数器记账。区分靠上面 ①②③。)memperf/appsamp/decomp_probe*/granule_test)均以 iOS SDK 交叉编译、ldid 注入 platform-application 签名后在设备上原生执行;采样通过 task_for_pid + task_info 与 host_statistics64/sysctl vm.compressor_* 完成,不依赖任何模拟。方法:每次重新 mmap(MAP_ANON|MAP_PRIVATE) 后逐页写入 1 字节触发零填充次要缺页(16KB/页),mach_absolute_time() 计时、getrusage 计数,5 次重复取中位数;随机模式用 Fisher–Yates 打乱页序。
我们将 XNU 源码树中的 WKdmCompress_16k.s / WKdmDecompress_16k.s / WKdmData.s(即内核压缩器在 arm64 16K 页上执行的同一段汇编)直接汇编链接进测试二进制,在真机上测量内核真实路径的性能上限:
c_segment_sv_hash 单字存储路径(源码 vm_compressor.c L3952-3960),解压近似 memset。RANDOM 页被识别为不可压后原样存储(ratio=1.0,"压缩"吞吐 13857 MiB/s 实为检测+memcpy 成本)。方法:fork N 个独立地址空间(绕过 iOS 单进程驻留上限),各自 mmap 并填充高压缩性 text 数据,父进程 2s 步进采样全局压缩器字节/页计数器。
vm.compressor_input_bytes 增量为 0 —— iOS 14.8 在空闲页充裕时完全不压缩,宁可把冷页留在 inactive 队列;② aggressive(8×384MB):2 秒内 free 2.96GB→42MB 触发安全停机,压缩器同期仅消化 (≈46MB/s 的突发处理速率),远追不上 ~1.5GB/s 的子进程缺页填充速度 —— 压缩器是滞后、限速的兜底,不是并发回收通道;③ 实测聚合比率 落在 WKdm TYPICAL 区间(§3.1 ratio ),佐证 bulk 路径主体走 WKdm 系编码。方法 v1:6 个子进程各映射 320MB text 数据并触碰一次(成为冷脏页),等待压缩器稳定后令其逐页重读(每 16KB 页读 1 字节 = 恰好一次潜在解压缺页),全程读 vm.compressor_decompressions 与 ru_minflt。
前文合成数据(TYPICAL/text 填充)回答"算法有多快",本节回答"真实应用的内存有多难压、压/解各多快"。方法链三件套(均为本会话新增仪器):
mach_vm_page_query,只转储 dirty+present 页(vm_compressor 的真实作用人群)。普查显示真实进程 RW 虚拟地址空间中仅约 4% 被触碰变脏(如 discover:46025 已分配未触碰 / 1801 脏 / 473 已逐出)——"应用申请了很多、真正用到的很少"。memcmp 往返校验)。mach_vm_read_overwrite 强制内核走真实解压缺页路径(vm_fault → c_decompress_page),每页前后各读一次任务的 compressed 计数器——每次读是解压还是零填充由独立内核计数器逐页标注,非推断。同一守恒律在注入式实验(realprobe,把 168MB 真实脏页注入自身进程、老化、深压、逐页重读)上独立复核:
主应用(微信/淘宝等)无法在前台活跃态转储——实验期间设备锁屏、SpringBoard 拒绝 uiopen 启动(系统应用同样拒启,验证非越狱工具问题);因此 5b.1 语料来自真实应用的 widget/扩展进程(哔哩哔哩×2、淘宝 widget、News 通知服务、系统通知服务、discover)+ 美团与 Weather 主应用的挂起态(5b.2 由 appwake2 直接测其压缩页)。扩展进程与应用主体使用相同框架与堆分配器,其脏页属真实应用内存;但与"前台重度使用"的堆形态可能有差异,特此声明。另:mach_vm_page_query 的 PAGED_OUT 位实测标识的是文件页逐出(external pager)而非压缩器页——本节早期用该位筛选"压缩页"的读法已被计数器守恒法取代。
vm.compressor_swapouts_under_300s=0),全部就地压缩。compressor_decompressions / reactivations 增长加速 —— 被压缩的挂起应用在其(少量)被再次触碰的页上付出解压成本,而前台应用受 vm_pageout 保护。表:挂起应用在 6×384MB 压力(free 下探 348-518MB)期间完全冻结 —— faults Δ=0、压缩字节不变:它们早已被压缩过(稳态即完成),且未被唤醒。metacompressor() 先 WKdm,失败或产出 ≥ 阈值再试 LZ4 择优(vm_compressor_algorithms.c L296-405);设备 vm.lz4_threshold 实测 12288 = 源码 arm64 16K 页的编译期设定(L453),配置与二进制一致。② wk/lz4_compressions 恒 0 的"反常":RELEASE 内核 VMCSTATS=(DEVELOPMENT||DEBUG) 把计数语句编译为空(L122-140)—— 计数器不可用 ≠ 算法未使用,不能据此判断 WKdm/LZ4 占比(此前多份分析踩过此坑)。③ 解压缺页路径:vm_compressor.c c_decompress_page L4077 → metadecompressor L4311 分派;每次线程解压计数 vm_fault.c L163(正是本报告 appsamp/decomp_probe 采样的那组计数器)。以下恒等式在原始数据上程序化复核(site/audit.py),任何一条失败即整体判废:
iPhone 12 Pro(D53pAP)· iOS 14.8 (18H17) · Darwin 20.6.0 · A14 6 核 · 6GB · Taurine 越狱 · 16KB 页。
macOS 侧:xcrun -sdk iphoneos clang 交叉编译 + ldid 签名;USB 经 iproxy 2222→22,paramiko 执行。
设备侧工具:/var/mobile/ios_perf/{memperf,appsamp,decomp_probe2}(本仓库 ios-perf-bench/bench/)。
memperf pagefault:4/16/64/256MB × seq/rand × 5 reps,mmap 冷启动。
granule_test:页粒度判别 —— 每块触碰 1 点 vs 块内 4 点(0/4096/8192/12288)vs 块内 2 点(0/8192),三相对比 ru_minflt;16KB 页下三者缺页数相等,4KB 页下为 1×/4×/2×。
memperf compression:LZ4/LZ4_RAW/LZFSE/LZMA/ZLIB × zero/text/mixed/random × 64KB/256KB/1MB/4MB × 5 reps,往返 memcmp 校验。
memperf wkdm:XNU WKdm 16K 汇编(ALL_ZEROS/MOSTLY_ZEROS/TYPICAL/RANDOM)。
memperf mproc:N 进程 × per_mb × hold,2s 步进全局采样;free<96MB 安全停机。
appsamp:task_info(VM/EVENTS) + host_statistics64 + vm.compressor_* @250-500ms。
appdump2:mach_vm_region_recurse 枚举 RW 区域 + mach_vm_page_query 逐页 disposition,只转储 dirty+present 真实脏页(manifest 含页面形态普查)。
realcodec:内核 WKdm 16K 汇编(WKdmCompress_16k.o/WKdmDecompress_16k.o)直跑真实脏页转储,逐块 memcmp 往返校验 + 比率直方图。
appwake2:对挂起应用逐页 mach_vm_read_overwrite 强制内核解压缺页,每页前后读 TASK_VM_INFO.compressed 逐页归类(解压 vs 零填充),含驻留读对照组。
realprobe:真实脏页语料注入自身进程 → 老化 → 自适应不可压施压(消化窗口)→ SIGUSR1 逐页重读,父进程 250ms 采样子进程 compressed 曲线。
granule_test:页粒度判别(见 §1 验证链)。
decomp_probe v1/v2:冷页老化 + 逐页重读,解压缺页计数。