# 性能

测量环境：Apple M5 Pro，macOS 26.5，Node 26.7，固定 MoonBit 工具链。同类库固定为 Magic486 `8fecb90`、JSJ222 `ee7d3be`。全部原始样本、源码摘要和可执行文件摘要保存在 `reports/peer-benchmark.json` 和 `reports/peer-resources.json`。

```sh
npm run compare:peers        # 拉取并固定同类源码
npm run benchmark:peers      # 核心展开基准（JS release）
npm run benchmark:resources  # 四后端复杂负载，耗时与峰值内存
```

## 核心展开（JS release）

预热 3 次，7 轮，每轮轮换三家的执行顺序，表中为中位数。单位是每个样本的毫秒数，每个样本内三家的迭代次数相同，并校验输出。

| 场景 | 方式 | 次数 | 本项目 | Magic486 | JSJ222 |
| --- | --- | --- | --- | --- | --- |
| 标量路径 | 每次解析 | 10000 | **3.692** | 5.457 | 7.199 |
| 标量路径 | 复用模板 | 10000 | **1.513** | 4.081 | 5.119 |
| Unicode 查询和列表 | 每次解析 | 10000 | **8.917** | 15.666 | 17.552 |
| Unicode 查询和列表 | 复用模板 | 10000 | **5.431** | 13.430 | 14.936 |
| 50 个表达式 | 每次解析 | 500 | **4.271** | 10.515 | 10.405 |
| 50 个表达式 | 复用模板 | 500 | **1.325** | 8.767 | 8.847 |
| 大值超出输出预算 | 每次解析 | 100 | **2.847** | 78.735 | 4.124 |
| 大值超出输出预算 | 复用模板 | 100 | **2.803** | 76.041 | 4.052 |

最后两行差距大，是因为本项目和 JSJ222 在写入前检查预算，Magic486 先生成片段再检查。

## 复杂负载（四后端）

每库每场景 5 个独立进程，表中为中位数；耗时只计业务循环。“—”表示该库没有对应的公开接口。

| 负载 | 内容 |
| --- | --- |
| 512 变量展开 | 512 个表达式，各绑定一个标量 |
| 512 条契约校验 | 512 个必填标量契约，重复校验 |
| 200 链接改 1 个 | 200 个端点的会话，每次只改影响 1 个端点的变量 |
| 200 链接全更新 | 所有变量同时变化 |
| 1 个变量影响 200 链接 | 一个共享变量变化，200 个端点都要重算 |
| 保留 1001 个会话快照 | 同“改 1 个”，但保留全部历史快照 |
| 200 请求完整批量重算 | 每次重新展开全部 200 个请求 |
| 200 模板策略审计 | 一半模板违反策略 |
| Unicode 列表与关联集合 | 1024 个列表成员和 128 个关联成员，含中文、emoji、空格、`/`、`%` |

耗时（ms）：

| 后端 | 负载 | 本项目 | Magic486 | JSJ222 |
| --- | --- | --- | --- | --- |
| js | 512 变量展开 | **16.051** | 52.693 | 59.035 |
| js | 512 条契约校验 | **28.383** | — | 32.478 |
| js | 200 链接改 1 个 | **3.211** | — | 10.980 |
| js | 200 链接全更新 | **22.872** | — | 31.968 |
| js | 1 个变量影响 200 链接 | **14.821** | — | 27.204 |
| js | 保留 1001 个会话快照 | **3.136** | — | 17.748 |
| js | 200 请求完整批量重算 | **39.704** | — | 108.528 |
| js | 200 模板策略审计 | **22.726** | — | 31.691 |
| js | Unicode 列表与关联集合 | **28.011** | 45.848 | 45.584 |
| wasm | 512 变量展开 | **34.973** | 59.767 | 99.666 |
| wasm | 512 条契约校验 | **39.138** | — | 52.656 |
| wasm | 200 链接改 1 个 | **5.243** | — | 19.244 |
| wasm | 200 链接全更新 | **55.957** | — | 56.881 |
| wasm | 1 个变量影响 200 链接 | **39.087** | — | 41.562 |
| wasm | 保留 1001 个会话快照 | **5.319** | — | 17.206 |
| wasm | 200 请求完整批量重算 | **160.365** | — | 185.984 |
| wasm | 200 模板策略审计 | **41.006** | — | 124.649 |
| wasm | Unicode 列表与关联集合 | **30.346** | 50.899 | 64.076 |
| wasm-gc | 512 变量展开 | **9.831** | 13.678 | 20.862 |
| wasm-gc | 512 条契约校验 | **15.464** | — | 18.820 |
| wasm-gc | 200 链接改 1 个 | **1.645** | — | 5.888 |
| wasm-gc | 200 链接全更新 | **13.895** | — | 14.471 |
| wasm-gc | 1 个变量影响 200 链接 | **8.051** | — | 11.810 |
| wasm-gc | 保留 1001 个会话快照 | **2.332** | — | 14.191 |
| wasm-gc | 200 请求完整批量重算 | **26.904** | — | 38.773 |
| wasm-gc | 200 模板策略审计 | **8.861** | — | 23.797 |
| wasm-gc | Unicode 列表与关联集合 | **19.391** | 32.534 | 30.086 |
| native | 512 变量展开 | **12.975** | 21.820 | 37.873 |
| native | 512 条契约校验 | **13.553** | — | 25.543 |
| native | 200 链接改 1 个 | **0.895** | — | 6.706 |
| native | 200 链接全更新 | **20.683** | — | 21.361 |
| native | 1 个变量影响 200 链接 | **13.415** | — | 16.478 |
| native | 保留 1001 个会话快照 | **0.878** | — | 6.160 |
| native | 200 请求完整批量重算 | **48.504** | — | 64.223 |
| native | 200 模板策略审计 | **15.445** | — | 47.928 |
| native | Unicode 列表与关联集合 | **14.460** | 18.998 | 24.889 |

36 组的耗时中位数全部最低，进程峰值内存有 21 组最低。

峰值内存：

| 后端 | 负载 | 本项目 MB | Magic486 MB | JSJ222 MB |
| --- | --- | --- | --- | --- |
| native | 保留 1001 个会话快照 | **3.6** | — | 15.8 |
| wasm-gc | 保留 1001 个会话快照 | **21.2** | — | 47.7 |
| js | 保留 1001 个会话快照 | **67.8** | — | 92.6 |
| js | Unicode 列表与关联集合 | 90.8 | 125.6 | **90.7** |
| js | 200 链接改 1 个 | 70.9 | — | **60.3** |
| js | 200 链接全更新 | 77.0 | — | **70.2** |

除保留快照外，native 下三家的峰值内存相差不超过 0.3 MB；wasm 下相差 0.5–5 MB，互有高低（例如 512 变量展开中 Magic486 最低）。全部数据见报告。

JS 后端的“改 1 个”和“全更新”两类会话负载中，本项目的峰值比 JSJ222 高 7–11 MB。这部分内存来自 V8 的后台编译器，不是库的数据：

| 测量（JS，200 链接改 1 个） | 本项目 | JSJ222 |
| --- | --- | --- |
| 默认峰值 RSS | 71 MB | 60 MB |
| 关闭后台并发编译（`--no-concurrent-recompilation`）的峰值 RSS | 59.5 MB | 59.4 MB |
| 关闭 Maglev 内联（`--no-maglev-inlining`）的峰值 RSS | 60–63 MB | 61 MB |
| 运行中 JS 堆的最大占用（`--trace-gc`） | 10.3 MB | 9.9 MB |
| 编译器 zone 内存峰值（`--trace-zone-stats`） | 12.6 MB | 3.0 MB |

峰值时刻有 46 个 Maglev 编译任务同时存活，合计约 8.4 MB。本项目的循环每次更新只需几微秒，很多小函数几乎同时变热，后台编译任务因此集中排队。这是 JIT 预热期的一次性开销，不随会话规模或保留的快照数增长：保留 1001 个快照的场景里，本项目反而比 JSJ222 低 25 MB。

## Node SDK 会话

SDK 的会话在 JS 宿主层实现，单独测量（200 个端点）：

| 场景 | 改进前 | 现在 |
| --- | --- | --- |
| 改 1 个变量、重算 1 个端点 | 0.063 ms | 0.006 ms |
| 保留 1001 个快照，每个快照的额外堆内存 | 16.2 KB | 1.8 KB |
| 会话中另有 2 万成员的列表（不变），改 1 个标量 | 1.18 ms | 0.002 ms |

`compileTemplate(...).expand` 单次调用约 2 µs，其中包括 JS 对象快照、JSON 往返以及核心展开。
