mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
## 实测故障
聊天页长时间挂着之后 GUI 卡死。CDP 抓生产实例(2588 节点):
Mesh/SphereGeometry 2588 个 geometry 数据合计 22.67MB
Sprite/BufferGeometry 1294 个 label 纹理,256×64 RGBA ≈ 64KB/个
进程常驻内存反复冲上 GB 级、被 GC 拉回后又再度暴涨(实测 986MB ↔ 3.8GB
震荡),CPU 稳定 30%(多线程耗在 GC 与对象构建),句柄数稳定 490 ⇒
不是句柄泄漏,而是持续的 GPU 资源分配。
## 两个叠加缺陷
1. **几何体从不共享**。每个节点 `new THREE.SphereGeometry(rad, 16, 12)`、
每个光晕球 `new THREE.SphereGeometry(gr, 16, 12)` —— 半径各异看起来
「只能各自 new」。但 three.js 里大小应由 mesh.scale 表达,几何体应共享。
2. **重建时不 dispose**。buildChatStarmapGraph 只 `starmapScene.remove(m)`,
从不 dispose()。remove 只把对象从场景树摘下来,geometry/material/texture
仍占着 WebGL 资源。全代码搜不到 dispose() 就是铁证。星图每次全量重建
泄漏一整轮,节点数还随记忆增长 ⇒ 泄漏只增不减。
## 修法
- `starmapSphereGeometry()`:建一次半径 0.5 的球,全场景共用。
**半径必须仍是 0.5** —— 节点缩放基准 `baseScale = rad / 0.5` 的分母
就是它,改成 1 会让所有节点缩放翻倍,且与脉冲结束时的
`setScalar(baseScale)` 复原逻辑不自洽。
- `disposeStarmapObject()`:递归 traverse 子树(节点下挂着 glow sphere
与 label sprite,只 dispose 顶层会漏),释放 geometry/material/texture;
用 seen 集合防重复释放,并**排除共享几何体**(释放它会让仍在渲染的
mesh 变黑/报错)。
- 重建时节点与边都走 dispose。
几何体数据从 2588 份降到 1 份(22.67MB → 9KB),label 纹理由
「只增不减」变成「每轮释放」。
## 判据(cmd/gui/starmap-gpu-lifecycle.test.mjs)
13 条。变异测试验证非假红:
- 还原 `new SphereGeometry(rad,…)` ⇒ 「节点循环用共享几何体」+
「代码里只有一处构造」转红
- `disposeStarmapObject(m)` 换回 `starmapScene.remove(m)` ⇒
「重建时释放旧节点资源」转红
排障中判据自身报过 3 次假红,根因都写进注释:
- 注释里也写着 `starmapNodeMeshes.forEach` 与 `disposeStarmapObject`,
裸正则从注释开始匹配 ⇒ 改为先剥注释
- 匹配窗口 200 太大:节点那处换成 remove 后,**边**的
`disposeStarmapObject(l)`(相距 84 字符)仍落在窗口内 ⇒ 收到 40
- 摘要里 `new SphereGeometry` 计数包含注释里的引用,显示 2 次而真实
只有 1 次 ⇒ 计数前先剥注释
## 验证
6 个门禁全绿:starmap-gpu-lifecycle / window-liveness /
device-bridge-liveness / endpoint-align / device-align /
device-gateway-discovery。