Repository navigation
fix(captcha): 修复 serve 常驻进程 RSS 单调增长(issue #50) - #51
Merged
Merged
Conversation
根因(三个复合): 1. 复用窗口内每个 solve 无条件重新调用 initAliyunCaptcha,旧 SDK 实例图 (pe VM/FeiLin 心跳/XHR 缓冲)滞留在窗口里,REUSE_MAX_SOLVES=25 时 单世代峰值可达数百 MB;窗口销毁后 JSC 不把页归还 OS,峰值成为 RSS 永久地板——台阶式只涨不跌,2.9 天实测 9.95GB 2. _requestLog 每个窗口内 fetch 都 push、从不截断(无界,量级小但确定) 3. _memCdnCache 按 pe 版本轮换只增不减(每版本数百 KB 常驻) 修复: - REUSE_MAX_SOLVES 25→8:世代滞留峰值压到原来 ~1/3,CPU 摊销损失可忽略 - destroyDom 尾部接管式节流 full GC(Bun.gc(true),默认 5s 一次, CAPTCHA_GC_MIN_INTERVAL_MS 可调):世代交替点把死对象图收掉、促使 JSC 归还页;pe-storm 连续销毁由节流兜底 - _requestLog 改环形(cap 256,stall 检测只读最新条目/诊断只看当前 solve 的最后 12 条,语义不变) - _memCdnCache 加 FIFO 帽(16 条,磁盘缓存仍可回读) - 删除死数组 solveTimes - __captchaMemStats() 导出测试/调试观测面 验证:bun x tsc --noEmit 通过;859/859 测试过(含 4 个新 memory guards 用例)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #50
根因
转发管线(proxy/handler.ts)每请求都是干净的函数作用域,不是泄漏源。问题出在 captcha 子系统,三个因素复合成“台阶式只涨不跌”:
solveTraceless在复用的 happy-dom 窗口上无条件重新调用w.initAliyunCaptcha(...),每个 solve 在同一窗口里实例化一套新的 Aliyun SDK + pe 字节码 VM + FeiLin 指纹 SDK + 2s 心跳 interval,旧实例能否释放取决于 SDK 内部(实测滞留约十几 MB/solve)。REUSE_MAX_SOLVES=25期间单世代峰值可达数百 MB。destroyDom的逻辑清理是完备的(happyDOM.close + 别名 refcount/tombstone 卸载 + guest scope 移除),但 Bun/JSC 只在 full collection 时才把页归还 OS——每个窗口世代的分配峰值成为 RSS 的永久地板。这解释了 issue 里的台阶曲线和 2.9 天 9.95GB。_requestLog每个窗口内 fetch 都 push 从不截断;_memCdnCache按 pe 版本轮换只增不减(每版本数百 KB 常驻进程生命周期)。空载 +1MB/s 的形态与池子稳态补铸(min=15、TTL 95s ≈ 每 6.3s 一个 solve)吻合;deep-idle(900s)停铸后走平,与报告人“静置 8 分钟一条平线”的观测一致。
修复
REUSE_MAX_SOLVES25→8destroyDom尾部节流 full GCBun.gc(true)(默认 5s 节流,CAPTCHA_GC_MIN_INTERVAL_MS可调);世代交替点收掉死对象图、促使 JSC 归还页;pe-storm 连续销毁窗口由节流兜底,不会每个失败 solve 都付一次 stop-the-world_requestLog环形化(cap 256)_memCdnCacheFIFO 帽(16 条)solveTimes__captchaMemStats()权衡说明
Bun.gc(true)是同步 stop-the-world,可能上百 ms;5s 节流把它限制在世代交替点,且可用 env 调成 0(关闭节流)或更大值(几乎禁用)。验证
bun x tsc --noEmit通过bun test859/859 通过(含 4 个新增 memory guards 用例:环形截断、CDN 缓存 FIFO、GC 节流、复用档位默认值)遗留建议(不在本 PR 内)
MemoryMax作为深度防御(issue 报告人的 workaround 已验证有效)CAPTCHA_POOL_MIN(当前 15)X-Device-Mid3001 问题已在 v4.6.8 修复(6b7327e),回复 issue 时可确认