> For AI agents: the complete documentation index is available at https://renmori.mewbaka.cn/llms.txt, the full documentation bundle is available at https://renmori.mewbaka.cn/llms-full.txt.

# 真实游戏实测

本页记录 RenMori 1.2.0 在一款真实 GalGame 发行版构建上的实测结果：以同一份构建的原版与 RenMori 完整保护版为对照，在同一台设备上测量顺序读取吞吐、随机读取延迟与冷启动延迟；受保护版通过原生 launcher 启动，与玩家实际运行的方式一致。

与 [性能基准](https://renmori.mewbaka.cn/milestones/benchmark.md) 使用的合成资源不同，本页的样本是一款真实作品的发行版构建，资源规模约 3.5 GB，包含 CG、立绘、UI 素材、BGM、语音与视频；本页不公开该作品的名称。

## 结论摘要

对玩家而言，加密几乎无感。

- 随机读取的额外延迟最大约 0.15 ms，不足 60 FPS 下单帧时间（16.7 ms）的 1%
- 冷缓存下全部资源的顺序读取吞吐为 584 MB/s，是实时音视频解码所需带宽的百倍以上
- 平均大小约 1.9 MB 的单张图像，冷缓存下读取耗时增加约 1.8 ms，且 Ren'Py 通常在后台预加载图像
- 冷启动至首帧的耗时由 7.16 s 增加到 8.44 s，额外的 1.3 s 只在启动时发生一次，进入游戏后不再出现
- 受保护版 `game/` 目录体积仅增加 0.09%，其中包含三个平台的原生运行时

## 测试环境

| 项目      | 取值                                            |
| ------- | --------------------------------------------- |
| 测试日期    | 2026-10-31                                    |
| 设备      | Apple M1，8 GB 内存，内置 SSD                       |
| 操作系统    | macOS 26.5.1（arm64）                           |
| Ren'Py  | 8.5.2.26010301                                |
| RenMori | 1.2.0，完整保护（poly），启用 lockdown，通过原生 launcher 启动 |

## 测试样本

原版为作品的发行版构建，`game/` 目录共 3.51 GiB，资源存放于一个 2.05 GiB 的 RPA 封包与两个独立的视频文件中；受保护版由同一份构建经 `renmori protect` 生成，全部资源位于加密容器 `renmori.rmc` 中。

测试只比较两个构建中均存在且大小一致的条目，共 1407 个，合计 3593 MB；22 个已编译脚本（`.rpyc` 与 `.rpymc`）在受保护版中经过脚本层变换，大小与原版不同，不计入读取测试。

| 类别 |  文件数 |      合计 |
| -- | ---: | ------: |
| 图像 |  774 | 1477 MB |
| 音频 |  599 |  540 MB |
| 视频 |    2 | 1497 MB |
| 脚本 |   21 |  0.3 MB |
| 其他 |   11 |   79 MB |
| 合计 | 1407 | 3593 MB |

本页中的 MB 均指 2<sup>20</sup> 字节。

## 测试方法

全部测量均在引擎进程内进行，并通过引擎自身的资源加载路径 `renpy.loader.load` 读取，因此受保护版的数据包含解密、认证与容器索引查找的全部开销；两个构建均直接运行 `.app` 中的可执行文件，受保护版因此经过 launcher 的启动流程。

### 冷缓存与热缓存

每次冷缓存测量前，先以 APFS 克隆（`cp -c`）复制一份全新的构建；克隆与原文件共享磁盘数据，但在操作系统看来是新的文件，页缓存中不存在其任何内容，因此首次读取必然访问磁盘。预先验证显示，克隆后首轮随机 4 KB 读取的中位延迟为 104 µs，第二轮为 1.4 µs，证实首轮确为冷缓存。

热缓存测量在同一份克隆上重复读取，此时数据已位于页缓存中，结果只反映 CPU 开销。

### 测量项目

| 项目              | 方法                                                                           |
| --------------- | ---------------------------------------------------------------------------- |
| 顺序读取            | 以 1 MB 为单位完整读取全部 1407 个条目；第 1 轮为冷缓存，第 2 至 4 轮为热缓存，取中位数；共进行 3 次，每次使用全新克隆      |
| 随机 4 KB / 64 KB | 在最大的 64 个文件（均不小于 4 MB，合计 2214 MB）中随机选择文件与偏移，seek 后读取 4 KB 或 64 KB，各采样 2000 次 |
| 随机打开小文件         | 在 822 个不大于 256 KB 的文件中随机选择，打开并完整读取，采样 1000 次                                 |
| 冷启动             | 从运行可执行文件开始，到引擎绘制第一帧为止；冷启动每次使用全新克隆，共 5 次；热启动在同一份克隆上预热 1 次后测量 5 次              |

随机读取的冷、热两轮使用相同的随机序列，3 次测量的全部样本合并后计算中位数与 p95。

## 结果

### 顺序读取

单位为 MB/s，数值越大越好。

| 类别 | 原版（冷） | 受保护版（冷） | 原版（热） | 受保护版（热） |
| -- | ----: | ------: | ----: | ------: |
| 图像 |  1154 |     555 |  1302 |     480 |
| 音频 |  1132 |     430 |  1022 |     480 |
| 视频 |  1895 |     658 |  2281 |     557 |
| 脚本 |   118 |      85 |    96 |      75 |
| 其他 |  1644 |     568 |  1621 |     458 |
| 全部 |  1303 |     584 |  1547 |     419 |

受保护版的冷缓存吞吐约为原版的 45%，热缓存约为 27%；热缓存下已不存在磁盘等待，受保护版约 420 至 560 MB/s 的吞吐即为当前解密的上限。

按冷缓存吞吐换算，读取一张平均大小的图像（约 1.9 MB），原版约需 1.6 ms，受保护版约需 3.4 ms；视频与 BGM 由引擎流式读取，其码率通常仅为每秒数 MB，与 584 MB/s 相差两个数量级以上。

### 随机读取

单位为 ms，数值越小越好。

| 测试       | 缓存 | 原版中位数 | 受保护版中位数 | 原版 p95 | 受保护版 p95 |
| -------- | -- | ----: | ------: | -----: | -------: |
| 随机 4 KB  | 冷  | 0.216 |   0.181 |  0.443 |    0.399 |
| 随机 4 KB  | 热  | 0.200 |   0.187 |  0.479 |    0.456 |
| 随机 64 KB | 冷  | 0.252 |   0.403 |  0.452 |    0.760 |
| 随机 64 KB | 热  | 0.249 |   0.348 |  0.397 |    0.699 |
| 随机打开小文件  | 冷  | 0.196 |   0.265 |  0.937 |    0.988 |
| 随机打开小文件  | 热  | 0.100 |   0.143 |  0.438 |    0.675 |

随机 4 KB 读取两者相当，差异在测量误差范围内；随机 64 KB 读取的中位数增加 0.10 至 0.15 ms，原因是一次 64 KB 读取通常跨越两个分块，需要解密并认证两个分块；随机打开小文件的中位数增加 0.04 至 0.07 ms，来自容器索引查找与逐文件密钥派生。

### 冷启动

单位为 s，从运行可执行文件开始计时，取中位数，括号内为最小值与最大值。

| 阶段     | 缓存 |              原版 |            受保护版 |    差值 |
| ------ | -- | --------------: | --------------: | ----: |
| 资源索引就绪 | 冷  | 3.13（2.46–3.82） | 3.18（2.80–3.74） | +0.05 |
| 绘制首帧   | 冷  | 7.16（6.01–7.70） | 8.44（7.99–9.04） | +1.28 |
| 资源索引就绪 | 热  | 0.97（0.72–1.07） | 0.76（0.65–1.33） | −0.21 |
| 绘制首帧   | 热  | 5.05（3.82–6.50） | 5.83（4.61–6.54） | +0.78 |

launcher 的启动流程与容器索引的建立几乎不增加耗时，冷缓存下资源索引就绪的时间仅相差 0.05 s；热启动各次之间波动较大，两者的差异以冷启动数据为准。

额外的耗时集中在脚本加载阶段：为避免在磁盘上留下明文，受保护版不写入 Ren'Py 的字节码、界面分析等运行时缓存，每次启动都需重新编译脚本中的 Python 代码；单次运行的 Ren'Py 日志中，「Loading script」阶段原版为 169 ms，受保护版为 1967 ms。

### 体积开销

| 构建   |       `game/` 体积 |
| ---- | ---------------: |
| 原版   | 3,768,321,012 字节 |
| 受保护版 | 3,771,724,069 字节 |
| 差值   |           +0.09% |

受保护版的体积包含加密容器、运行时加载器与 Windows、Linux、macOS 三个平台的原生运行时；仅加密容器相对原版资源的开销为 0.08%。

## 结果解读

玩家能够感知的性能问题主要是卡顿与等待：卡顿取决于单次读取能否在一帧之内完成，等待取决于大块资源能否及时就绪。随机读取最多增加约 0.15 ms，不足单帧时间的 1%；顺序吞吐即使在冷缓存下也远高于音视频流式播放所需的带宽；游玩过程中加密不会引入可察觉的卡顿或等待。

唯一可以察觉的差异是启动时多出的约 1 s，它来自不写明文缓存的安全取舍，只在启动时发生一次。

## 局限

- 未测量实际游玩中的帧时间，本页数据只覆盖资源读取，不包括图像解码、音频解码与渲染
- 仅在一台 Apple M1 设备上测试，Windows、Linux 与 Steam Deck 上的数据尚未测量
- 测试设备使用内置 SSD，机械硬盘上冷缓存读取受磁盘限制更明显，受保护版与原版之间的相对差距通常会缩小
- 热启动数据波动较大，仅供参考
- 样本作品与测量代码不公开，本页数据无法由第三方直接复现；可复现的合成基准见 [性能基准](https://renmori.mewbaka.cn/milestones/benchmark.md)
