性能与体积
Viva 的预算、实际测过的结果、未达标的地方,以及自己的代码里该避免什么。
Viva 为小体积和低空闲开销而设计。这些是设计目标,不是承诺。下面每个结果都来自仓库里的报告,对应报告中写明的机器和构建方式;它们是那台机器上的基线,不是对你机器的保证。
预算
对一个最小的原生应用:
| 预算 | 目标 |
|---|---|
| 剥离后的可执行文件 | 不超过 4 MiB(超过 8 MiB 需要复核) |
| 预热启动到首个可交互帧 | 不超过 50 ms |
| 空闲常驻内存 | 不超过 15 MiB |
| 空闲 CPU、GPU 提交与呈现 | 实际为零 |
| 空闲时框架的 goroutine | 不超过 2 个 |
| 未变化的一帧 | 不布局、不重建场景、不提交 GPU |
目标冲突时的顺序是:低内存,然后是运行性能,然后是小体积产物,然后是正确性,然后是易用性和跨平台一致性,最后才是可选的浏览器目标。
实际测过什么
M0 是最小的 macOS 窗口:一次 Metal 清屏与呈现,没有任何组件。测量环境是 Apple 芯片、macOS 15.5、Go 1.26.5,构建参数为 -trimpath -ldflags='-s -w -buildid='。
| 指标 | 结果 | 目标 | 结论 |
|---|---|---|---|
| 剥离后的可执行文件 | 1,697,506 bytes | 不超过 4 MiB | 达标 |
| 稳定后的 CPU | 0.0% | 实际为零 | 达标 |
| 空闲 GPU 提交 | 首次呈现后为 0 | 零 | 达标 |
| 真实 Metal 呈现后的物理内存占用 | 26.3–26.8 MiB | 不超过 15 MiB | 未达标 |
| 首个调度帧 | 123.075–373.643 ms | 预热不超过 50 ms | 未达标 |
报告对这两项未达标写得很明确。更早出现过的 15 MiB 数字是在尚未提交任何 Metal 命令时测的,已被否决,不作为基线。AppKit 与 Metal 的固定开销还没有和 Viva 自身的部分分开,所以内存目标保持不变,但目前未达到。完整报告含机器信息和复现命令,见仓库中的 docs/benchmarks/。
保留式场景(M1)清空一个未变化的 10,000 节点场景用时 2.012 ns 且无分配,更新 10,000 个节点中的一个用时 12.39 ns 且无分配。
自己的代码里该避免什么
只有应用也做到,Viva 才能把空闲开销保持为零。
- 不要靠定时器重绘。 状态变化时调用
Invalidator.Invalidate,其余时间让窗口休眠。 - 不要在
Paint里分配内存。 它在每次重绘时运行,框架自己的稳态路径也写成了尽量少分配、接近零。复用缓冲区,让每帧的工作量与变化量成正比。 - 回调要短。 它们在窗口线程上运行。慢的工作放到其他 goroutine,再通过
OnWake发布结果。 - 只链接用到的东西。 可选子系统放在各自的包和构建标签里,没用到的不会给你的二进制增加代码。
复现
benchmarks/ 目录里有 macOS 和 Linux 基线背后的脚本,每份报告都写明了产生它的命令。viva build 会单独报告程序本身的大小,不含周围的其他东西。