Files
gopeed/experiments/moejs/RESOURCES.md
T

6.9 KiB
Raw Blame History

CPU 与内存补充测量

日期:2026-11-14。沿用 主报告 的引擎版本、三个固定扩展包、回放输入和 M1 / Go 1.26.0 环境。

建议维持 goja,暂不投入完整替换。 在当前每次事件新建引擎、重新编译加载的方式下,B 站/YouTube 的 CPU 只减少约 12% / 15%,没有一致的内存优势;连续解析时峰值 RSS 更高。Twitter 的 CPU 降幅较大,但每次只省约 5 ms。这些收益不足以抵消完整宿主桥接、兼容性和维护成本。

测量方式

  • 每个样本使用新的独立 OS 进程,两个引擎交替先后顺序,5 轮重复,报告中位数;最终数据共 120 个进程样本。测量时未与本次其他构建或测试并发。
  • GOMAXPROCS=1 GOGC=100 GOMEMLIMIT=off,不使用 PGO。CPU 是 getrusage(RUSAGE_SELF) 的 user + system 时间,除以完成次数;包含 GC 和编译开销,不使用瞬时 CPU 占用百分比,也不把墙钟耗时直接当 CPU 时间。
  • cold:一次进程内先预热一次全局初始化,再连续完成 20 次“新建环境、克隆 bundle 输入字符串、编译加载、解析、关闭”。接近当前反复触发扩展事件的方式。每次使用独立 bundle 字符串,模拟生产文件读取后的输入所有权。
  • warm:环境已加载,连续解析 200 次。仅用于确认复用环境时的 CPU 上限;当前生产事件路径没有这样复用。
  • 内存组不预建引擎,从相同测量程序基线开始,分别建立并保留 1 / 8 个完整环境,每个环境执行一次解析后保持存活。8 个环境是同时保留,不是同时并行执行;不模拟实际 Blob/FFmpeg 媒体数据。
  • 存活堆:runtime.MemStats.HeapAlloc 相对建引擎前的增量。连续 GC 并给异步清理调度机会,至少 3 轮、最多 8 轮,直到相邻值差异小于 64 KiB;不稳定则测量失败。保留源字符串并用 runtime.KeepAlive 保证环境仍存活,避免编译器提前释放。
  • RSS:通过 ps 记录当前物理驻留快照,通过 getrusage 记录进程历史峰值;macOS 的峰值单位为字节,Linux 转换为字节。ps、稳定 GC 和内存快照都在计时区间外,RUSAGE_SELF 不包括 sampler 子进程 CPU。
  • 两个引擎链接在相同测量 worker 中,RSS 含公共 Go/测试框架/代码页和 allocator 保留页,不是完整 Gopeed 应用或最终单引擎产品的内存预测。存活堆增量用来区分扩展保留对象和进程历史峰值。
  • 全部输出按 SHA-256 比较一致,没有通过减少文件或请求处理量获得更好的数字。宿主 mock、HTTP fixture、未移植能力及真实下载尚未验证等限制与主报告相同。

冷路径 CPU 与连续解析峰值

扩展 goja CPU (ms/次) moejs CPU (ms/次) CPU 减少 goja 峰值 RSS (MiB) moejs 峰值 RSS (MiB)
bilibili 118.962 104.081 12.5% 154.7 172.3
youtube 278.476 237.330 14.8% 283.8 358.9
twitter 15.555 10.594 31.9% 79.7 96.8

峰值是连续 20 次冷解析期间整个 worker 的进程峰值,不是单个 runtime 的堆大小。峰值会受 Go GC/allocator 与异步清理时机影响;不能将它当作关闭后仍存活的对象。原始数据保留每轮值,汇总文件也提供 min/max。

扩展 goja 累计分配 (MiB/次) moejs 累计分配 (MiB/次) 分配减少
bilibili 73.69 60.17 18.3%
youtube 159.91 146.82 8.2%
twitter 10.96 7.73 29.5%

moejs 的累计分配量确实较少,但这没有转化为更低的连续解析峰值 RSS。B/op、GC 后存活堆、RSS 是不同指标,不能互相替代。

保留环境时的内存

扩展 保留环境数 goja 存活堆增量 (MiB) moejs 存活堆增量 (MiB) goja RSS 快照 (MiB) moejs RSS 快照 (MiB)
bilibili 1 15.87 15.66 114.2 111.2
bilibili 8 126.72 120.60 362.0 302.6
youtube 1 32.48 41.22 203.7 192.2
youtube 8 259.64 320.54 627.8 680.1
twitter 1 2.53 2.63 75.6 74.7
twitter 8 20.06 19.48 106.9 93.5

B 站一个环境的存活堆几乎没有变化;YouTube 反而更高。多环境情况下也没有稳定、普遍的显著节省。RSS 快照包含 allocator 页面,因此与存活堆的变化比例不同。

最初单次 GC 的 YouTube 堆快照约为 32.5 → 42.2 MiB。考虑 moejs 异步清理编译缓存后,已重测驻留组,表中使用稳定 GC 的结果,不能将初始 42.2 MiB 当成最终驻留值。CPU 和冷路径峰值取自第一次进程资源测量;这些计时和峰值发生在强制 GC 之前,不受驻留测量修正影响。

关闭全部环境并等稳定 GC 后,额外存活 Go 堆回落到 goja 约 0.03–0.05 MiB、moejs 约 0.18–0.97 MiB。这包含一次性进程缓存;本实验没有据此认定泄漏。RSS 不一定同步回落,不能只看关闭后的 RSS 判断对象是否已释放。

热路径 CPU

扩展 goja CPU (ms/次) moejs CPU (ms/次) CPU 减少
bilibili 19.688 3.173 83.9%
youtube 2.905 0.215 92.6%
twitter 3.265 0.453 86.1%

热路径的大幅 CPU 节省再次成立。但它要求持有并复用已加载的环境;对当前每个事件重建环境的实现,应该采用上面的 cold 结果评估迁移。

决策

按当前扩展和架构,CPU/内存补测没有提供足够的替换依据。尤其 B 站和 YouTube 的 CPU 节省有限,内存没有一致改善,加上主报告里压缩体积几乎不变,应先维持 goja,把本 PR 留作调研记录。

未来若出现长时间执行计算、反复复用环境的真实扩展,再重新评估;若独立研究编译缓存或环境复用,必须同时在 goja 和 moejs 上比较收益,不能把架构优化全部归给引擎替换。

复现和证据

cd experiments/moejs
python3 fetch_sources.py
python3 measure_resources.py > results/resources-run.txt
# 只重新汇总已保存的原始样本,不启动新测量
python3 measure_resources.py --summarize-only
# 必要时只重测驻留组,保留之前的 CPU 样本
python3 measure_resources.py --memory-only > results/resources-memory-run.txt

原始样本:resources.json;汇总:resources-summary.json。首次资源运行日志:resources-run.txt;稳定 GC 后重测驻留组日志:resources-memory-run.txt。首次日志中的驻留组已被后者替代。当前 worker:resource_worker_test.go;驱动:measure_resources.py;功能检查:resources-tests.txt。CPU/warm 组中单次 GC 的快照保留作原始记录,内存结论只使用重新测得的 retained 组。