配置 512 MiB 的 VM,实际占多少内存?¶
主要结论¶
配置 512 MiB 不等于宿主立即占用 512 MiB。在这组 64 MiB 应用工作集的静态测试中,默认 VM 与管理进程实际常驻约 179–181 MiB;内存卸载后约 36 MiB,每实例节约 80.0–80.4%;压缩卸载后约 40 MiB,节约 78.0–78.1%。包含文件缓存的产品组占用则从约 224 MiB 降到 19–25 MiB。 每个条件测一次,结论限于当前 Linux 配置与短观察窗口。
| 用户选择 | 这组数据说明什么 |
|---|---|
| 内存卸载 | 每实例节约 80.0–80.4% 常驻内存;含缓存的组占用也下降,下一次工具需要恢复 RAM |
| 压缩卸载 | 每实例节约 78.0–78.1% 常驻内存;更省磁盘 backing,停驻常驻约 40 MiB |
| 空闲释放 | 每实例节约 31.7–34.7% 常驻内存,但宿主仍保留文件缓存 |
| 内存压缩 | 重复内容每实例节约 18.9%;随机内容增加 18.2%,收益取决于可压缩性 |
| 共享快照+COW | 相同内容平均每实例节约 67.9–68.6%,独有随机内容节约 31.2%;完整改写后仍节约 30.4–31.7% |
| KSM | 观察 60 秒后,重复内容每实例节约 63.6%,相同随机内容节约 51.7%,独有随机内容节约 16.0% |
| daemon 内存池 | 每实例常驻约 61–124 MiB;重复 / 相同随机 / 独有随机内容的节约为 53.7% / 39.6% / 6.5% |
实验动机¶
512 MiB 是 guest 可使用的容量,不是 VM 在宿主上已经占用的物理内存。选择压缩、卸载或共享时,需要看实际宿主占用,以及下一次工具的恢复代价。只看 guest 空闲量或压缩率,都不足以判断机器省下了多少 RAM。
实验设计¶
所有 VM 固定为 512 MiB guest RAM、2 vCPU、64 MiB 应用数据。工作集保持一致:实际占用取决于触及的页面,因此不假设默认 VM 会用满 512 MiB。
空闲释放由应用主动释放测试工作集,VM 继续运行,需要再次使用时重新生成数据。内存卸载暂停 VM,将 RAM 状态保留在未压缩的 backing 中并卸载常驻 RAM,恢复后继续执行。压缩卸载使用压缩 backing 保存相同状态,减少存储占用,增加压缩和解压的代价。
- 单实例比较默认运行、空闲释放、内存压缩、内存卸载/压缩卸载。重复与确定性随机数据覆盖易压缩和难压缩内容;默认/内存压缩额外测可压缩的不同页面及 16 MiB 热区+48 MiB 冷区。
- 跨实例比较原始不共享、共享快照+COW、KSM、daemon 内存池:原始组独立启动四台私有匿名 RAM VM;共享组从同一 sealed 快照恢复;KSM 组使用相同的 RAM 映射,并开启去重建议;内存池组独立启动 VM,由 daemon 持有跨实例重复的物理页面;读取保持共享,写入时生成实例私有页。独有候选不提前复制进池,写入后扫描回收旧引用。使用相同工作集,检查 25%/100% 改写和独立退出。
- 每格一个新 VM 或新组,零预热。单实例观察 5 秒;KSM 在初始读数前观察 60 秒,其余跨实例方案观察 2 秒;不报告 P50/P95、置信区间或最终收敛。
常驻物理内存统计完整产品组的 VM、管理进程、压缩池/共享池和辅助进程,使用进程 PSS 之和,共享页面按比例计算。跨实例读数使用内核的进程汇总,避免逐映射取整;见 Linux 内存计量。宿主组内存使用完整 cgroup 的物理内存计费,包含计入该组的未映射文件缓存和内核开销。两个口径不能相加:前者回答进程实际常驻多少,后者防止忽略仍占 RAM 的缓存;共享页的归属方式也不同。两者都不等于整机新增的独占内存或生产容量。
Linux x86_64/KVM,AMD Ryzen 7 9700X,宿主内核 7.2.8-200.fc44.x86_64。完整组绑定逻辑 CPU 0–3、四核配额、零 swap;单实例组上限 2 GiB,跨实例四方案统一 4 GiB;协调器、观察者和全局 KSM 线程在组外。输入预先准备,不驱逐全局缓存;后台编译有记录,耗时仅为单次观察。单实例 16 个条件与新的跨实例 12 个条件分别来自独立静态批次,均通过数据、写入隔离、退出和来源检查,没有 OOM。
下面的命令设置 512 MiB VM 并开启对应功能。将 JOB、SOCKET、ATTEMPT 替换为启动输出中的身份。内存卸载从普通 VM 启动;压缩卸载先启用压缩 backing。内存压缩需要 userfaultfd 权限,压缩 backing 需要 FUSE。
# Default 512 MiB VM
pvisor run --executor vm --memory 512MiB -- claude
# Memory compression
pvisor run --executor vm --memory 512MiB --vm-cold-ram-compression -- claude
# Compressed backing for later offload
pvisor run --executor vm --memory 512MiB --vm-ram-compression -- claude
# Use the identities printed at startup
pvisor suspend JOB --vm-socket SOCKET --vm-job-id JOB --vm-attempt-id ATTEMPT --vm-offload
pvisor resume JOB --vm-socket SOCKET --vm-job-id JOB --vm-attempt-id ATTEMPT --vm-load
# KSM: without an explicit backing, Linux uses private anonymous RAM
pvisor run --executor vm --memory 512MiB --vm-ram-dedup -- claude
私有匿名 RAM 和恢复的私有 COW RAM 可以接受 KSM 建议;可写共享 RAM backing 会跳过。启用去重且不指定 backing 时,Linux 新 VM 使用私有匿名 RAM;该路径不支持整 VM offload。测试额外核验每台 VM 接受了去重建议,且 RAM 映射参与扫描,不能只凭命令接受就认定去重生效。共享基线数据也不代表四次独立 run。内存压缩与 RAM 去重不能组合,恢复的私有 COW RAM 不支持上述 live offload。详见控制选项和去重建议。
实验数据和分析¶
一台 512 MiB VM¶
每格 N=1,操作后 5 秒读数,单位 MiB。节约比例 =(默认实际常驻 − 当前实际常驻)÷ 默认实际常驻 × 100%,以相同工作集的默认运行作基准,用未舍入读数计算。512 MiB 是配置容量,不作为节约比例的分母。
| 方式 | 配置容量 | 实际常驻物理内存 重复内容 / 随机内容 |
每实例常驻节约比例 重复内容 / 随机内容 |
宿主组内存,含缓存 重复内容 / 随机内容 |
|---|---|---|---|---|
| 默认运行 | 512 | 181.4 / 179.4 | 基准 | 223.6 / 223.8 |
| 空闲释放 | 512 | 118.4 / 122.6 | 节约 34.7% / 31.7% | 223.3 / 223.7 |
| 内存压缩 | 512 | 147.2 / 212.1 | 节约 18.9% / 增加 18.2% | 131.2 / 195.8 |
| 内存卸载 | 512 | 35.6 / 35.8 | 节约 80.4% / 80.0% | 19.4 / 19.2 |
| 压缩卸载 | 512 | 39.8 / 39.5 | 节约 78.1% / 78.0% | 24.6 / 24.4 |
重复内容:64 MiB 应用数据由固定的字节序列反复填充,容易压缩,用于观察内容重复时的节约效果。随机内容:相同大小的数据由固定种子的伪随机序列填充,难以压缩,用于观察内容缺少重复时的效果。两种工作集的数据量相同,表头中的顺序对应每格的左右两个数值。
空闲释放后,常驻降至约 118–123 MiB,但含缓存占用仍约 223–224 MiB,因此不能宣称宿主已净回收同样多的 RAM。内存卸载同时降低两个读数,收益更明确。
内存压缩保持 VM 运行,只处理已驻留的冷块,保留未使用 RAM 的按需分配。重复内容常驻为 147.2 MiB,随机内容为 212.1 MiB;压缩不同页面为 146.4 MiB,冷热混合为 158.3 MiB,对应默认常驻为 179.8 / 177.8 MiB。扫描、编码和再次访问冷页时的解压消耗 CPU,节约取决于实际工作集。
卸载的存储与恢复代价¶
每格 N=1,耗时单位为 ms。先对比同样闲置 5 秒后、不卸载的默认 VM 执行相同测试任务的耗时。任务耗时从宿主发起操作开始,到完成 64 MiB 数据摘要、写入/fsync/读回校验为止;卸载组包含恢复 RAM 的时间。增加的耗时 = 卸载后任务耗时 − 相同工作集的不卸载任务耗时,使用未舍入读数计算。这是后台编译下的单次观测差值,不是稳定延迟保证。
| 方式 | 不卸载任务耗时 ms 重复内容 / 随机内容 |
卸载后恢复并完成任务 ms 重复内容 / 随机内容 |
增加的耗时 ms 重复内容 / 随机内容 |
|---|---|---|---|
| 内存卸载 | 276.5 / 320.1 | 432.4 / 498.2 | +155.9 / +178.1 |
| 压缩卸载 | 276.5 / 320.1 | 1730.3 / 766.2 | +1453.8 / +446.1 |
卸载操作发生在进入闲置状态时,另列如下;backing 为实际分配的磁盘块,单位 MiB。
| 方式 | 卸载操作 ms 重复内容 / 随机内容 |
backing MiB 重复内容 / 随机内容 |
|---|---|---|
| 内存卸载 | 44.1 / 98.1 | 186.4 / 186.3 |
| 压缩卸载 | 739.4 / 904.0 | 15.5 / 146.0 |
压缩 backing 在重复内容上更省存储,但需要编码、解码和临时内存。不要按停驻时的读数设置整个任务的内存上限;峰值、阶段 CPU 与完整样本口径保留在 CSV。
四台各 512 MiB 的 VM:方案对比¶
总配置容量为 2048 MiB。原始不共享是四台独立启动的 VM;共享快照+COW 使用同一个不可变 RAM 文件,修改时生成实例私有页;KSM 在独立启动的 VM 上开启内存去重建议。daemon 内存池从私有匿名 RAM 启动,把重复页面映射到池持有的同一份物理页;读取保持共享,写入使用 COW。除 KSM 组外,其余三组均未启用 KSM advice。
每实例常驻内存 = 完整产品组 PSS 合计 ÷ 4,包含分摊的辅助进程和 daemon 池组件开销。每格 N=1,单位 MiB。KSM 在初始读数前观察 60 秒,其余方案观察 2 秒;25%/100% 改写后的读数沿用统一短采样流程,没有再次等待 60 秒。节约比例以相同工作集、相同阶段的原始不共享组为基准,使用未舍入读数计算。
| 工作集 | 方案 | 每实例常驻 MiB | 每实例节约比例 | 100% 改写后每实例常驻 MiB | 改写后每实例节约比例 |
|---|---|---|---|---|---|
| 相同重复内容 | 原始不共享 | 132.8 | 基准 | 132.9 | 基准 |
| 相同重复内容 | 共享快照+COW | 41.7 | 68.6% | 91.2 | 31.3% |
| 相同重复内容 | KSM | 48.4 | 63.6% | 112.6 | 15.3% |
| 相同重复内容 | daemon 内存池 | 61.4 | 53.7% | 128.2 | 3.5% |
| 相同随机内容 | 原始不共享 | 132.3 | 基准 | 132.4 | 基准 |
| 相同随机内容 | 共享快照+COW | 42.4 | 67.9% | 92.2 | 30.4% |
| 相同随机内容 | KSM | 64.0 | 51.7% | 112.3 | 15.2% |
| 相同随机内容 | daemon 内存池 | 80.0 | 39.6% | 128.9 | 2.7% |
| 各实例独有随机内容 | 原始不共享 | 132.3 | 基准 | 133.7 | 基准 |
| 各实例独有随机内容 | 共享快照+COW | 91.0 | 31.2% | 91.3 | 31.7% |
| 各实例独有随机内容 | KSM | 111.1 | 16.0% | 111.2 | 16.9% |
| 各实例独有随机内容 | daemon 内存池 | 123.7 | 6.5% | 125.6 | 6.1% |
共享快照+COW 的收益包括共同系统状态和未改写的应用页面;完整改写 64 MiB 应用工作集后,系统页仍可能共享。独有随机内容会在准备阶段就增加私有页,因此初始节约较少。
KSM 在 60 秒内产生了实际页面合并;重复、相同随机、独有随机内容每实例常驻分别为 48.4/64.0/111.1 MiB。它合并实例内和跨实例的相同页面;独有随机数据仍需各自保存。完整改写会打破原来的共享页;改写后的读数没有再次等待 60 秒,不能代表重新收敛后的收益。每台 VM 都通过私有 RAM、去重建议接受字节和可合并标志检查。
daemon 内存池由宿主扫描跨实例重复的 4 KiB 页面,读取保持物理共享,写入使用 COW。 三种内容每实例常驻分别为 61.4/80.0/123.7 MiB,表中已计入池和辅助进程;完整组观测峰值为 537–546 MiB。扫描跳过未驻留页,只有实际回收的页才分配对象引用与校验信息,避免把配置容量转化成物理占用。独有候选只保留有界摘要,不搬入池;写入后扫描释放旧池引用。
物理共享池不压缩独有页,也不依赖 userfaultfd。相同内容读访问不会复制回私有 RAM;应用写入会生成私有页,再扫描时才回收旧引用。扫描、校验、页面传输、映射和管理信息仍消耗 CPU 与内存;因此专用方案并不保证胜过所有对照。共享快照从同一系统状态恢复,而池对照是独立启动的 VM,系统页能否共享取决于实际字节是否相同。改写后的短窗口只说明当时占用;池进程丢失会使依赖 VM 失败。
在 pvisor-daemon serve 命令中添加 --memory-pool 即可启用,默认关闭;池与 API 进程分离,可跨 API 重启保留对象。配置和预算见 daemon 指南。本轮测量的是实际 daemon 池组件与 VM 的路径,未启动完整 OpenSandbox API/SDK 数据面,不回答长期稳定性、真实 Agent 延迟或生产密度。
数据与复现¶
单实例读数 · 单实例观测差值 · 单实例来源 · 跨实例读数 · 跨实例观测差值 · 跨实例来源 · 复现命令
这些 CSV 只使用新的 512 MiB 静态批次,保留配置、N=1、常驻/缓存口径及源码、二进制、harness 和输入摘要关联。原始证据留在本地 .data/,不混入此前 256 MiB 或历史快照数据。