Keep investigation graphs stable during updates, defer expensive chart rendering, and prevent stale results when switching tasks. Adopt reference annotations and consolidate frontend documentation.
94 lines
5.9 KiB
Markdown
94 lines
5.9 KiB
Markdown
# Rive Persona 内存问题排查记录
|
|
|
|
> 历史记录:保留 Rive 内存故障与修复依据,当前指针通路、缓存与离线行为见 [Persona 设计](../agent-persona-design.md)。测试数量、失败列表与未提交状态只对应原记录时间,不代表当前回归结果。
|
|
|
|
日期:2026-07-21
|
|
|
|
## 背景
|
|
|
|
`next-webgis` 中的 Obsidian Persona 使用 Rive WebGL2 渲染。迁移到
|
|
`next-tjwater-frontend` 的 Vite、React 运行环境后,页面加载 Persona 时出现浏览器
|
|
`Out of Memory`,同时需要保留原有羽化灰黑球体的视觉效果。
|
|
|
|
本次排障验证使用 `@rive-app/react-webgl2@4.29.3`,依赖声明保留 4.x 兼容版本范围。
|
|
资源仍使用:
|
|
|
|
```text
|
|
https://ejiidnob33g9ap1r.public.blob.vercel-storage.com/obsidian-2.0.riv
|
|
```
|
|
|
|
## 已证实的触发条件
|
|
|
|
在同一 Chromium 环境下进行了对照测试。以下内存值是排障时的单次观测范围,
|
|
用于判断增长趋势,不应视为跨设备性能基准。
|
|
|
|
| 场景 | 结果 |
|
|
| ------------------------------------------------- | ----------------------------------------------- |
|
|
| Vite、WebGL2、绑定 Rive View Model | 渲染进程快速增长到约 4.6 GB,随后失去响应或崩溃 |
|
|
| Vite、阻止 `.riv` 加载 | 约 29 MB 至 61 MB,保持稳定 |
|
|
| Vite、Canvas、不绑定 View Model | 内存稳定,但渲染边缘和质感不符合原设计 |
|
|
| Vite、Canvas、调用 `bindViewModelInstance` | 再次出现持续增长 |
|
|
| Vite、WebGL2 4.29.3、调用 `bindViewModelInstance` | 再次出现持续增长 |
|
|
| Vite、WebGL2 4.29.3、不绑定 View Model | 约 71 MB 至 116 MB,最终约 78 MB |
|
|
| `next-webgis` 原实现 | 约 165 MB 至 221 MB,未出现持续增长 |
|
|
|
|
可以确认:在迁移后的 Vite 应用中,`bindViewModelInstance` 是泄漏的稳定触发点。
|
|
`useViewModelInstance` 内部也会执行该绑定,因此仅替换颜色 hook 不能解决问题。
|
|
|
|
不能仅凭现有证据断言缺陷完全属于 Vite、React 或 Rive 某一方。`next-webgis` 的同一
|
|
资源和完整绑定能够稳定运行,说明这是新运行环境与 Rive View Model 绑定生命周期的
|
|
兼容问题。若要定位到 Rive 内部对象,需要进一步制作最小复现并进行运行时级堆分析。
|
|
|
|
## 为什么不是 TypeScript 7
|
|
|
|
TypeScript 在该项目中只通过 `tsc --noEmit` 做静态检查。浏览器实际执行的是 Vite 和
|
|
SWC 转换后的 JavaScript。泄漏可以通过是否调用 Rive View Model 绑定稳定开关,因此
|
|
与 TypeScript 类型检查器无关。
|
|
|
|
## 最终修改
|
|
|
|
1. 保留 Rive WebGL2、Obsidian 资源和 `default` 状态机。
|
|
2. 移除 `useViewModel`、`useViewModelInstance`、`useViewModelInstanceColor` 及所有
|
|
`bindViewModelInstance` 调用。
|
|
3. 使用 CSS `brightness` 和 `contrast` 保持浅色界面中的灰黑视觉,不再监听并不存在的
|
|
应用深色主题。
|
|
4. Persona 仅在元素进入视口且页面可见时挂载,避免桌面和移动响应式节点同时初始化。
|
|
5. 首次初始化延迟到下一帧,使 React Strict Mode 的探测挂载可以在创建 Rive 实例前取消。
|
|
6. 保留懒加载和加载失败占位,但移除实验阶段的多皮肤、重复状态推导和无用事件透传。
|
|
7. 移除 Persona 环境变量开关,动画由组件生命周期直接管理。
|
|
|
|
## 回归保护
|
|
|
|
- `src/shared/ai-elements/persona.test.tsx` 验证加载的是 Obsidian 和 `default` 状态机,
|
|
同时保证不会调用 `bindViewModelInstance`。
|
|
- `src/app/app.e2e.ts` 验证页面只发出一次 `.riv` 请求。
|
|
- 桌面 1440 x 900 和移动端 375 x 812 均验证无横向溢出。
|
|
|
|
验证命令:
|
|
|
|
```bash
|
|
pnpm typecheck
|
|
pnpm lint
|
|
pnpm test
|
|
pnpm test:browser
|
|
pnpm build
|
|
```
|
|
|
|
## 后续修改约束
|
|
|
|
- 在独立最小复现和持续内存采样通过前,不要重新引入 Rive View Model 绑定。
|
|
- 不要用 CSS 隐藏两个已挂载的 Persona,响应式副本必须通过可见性挂载保持单实例。
|
|
- 不要移除 Strict Mode 延迟初始化,除非重新验证开发和生产生命周期。
|
|
- 更新 Rive 版本时,至少验证单次 `.riv` 请求、状态机切换、页面切换后的实例清理和
|
|
30 秒以上的浏览器进程内存趋势。
|
|
|
|
## 2026-10-21 原版恢复后的现状
|
|
|
|
Agent 入口使用基于原版 Obsidian 定制的冰水蓝资源。继续保留 Strict Mode 延迟初始化、按可见性挂载和禁止 View Model 绑定;配色直接写入资源,不应用旧版的 brightness / contrast 滤镜。`persona-resource.ts` 在页面内存与浏览器 Cache Storage 中缓存动画字节,按内容版本更新,不共享 Rive 实例或 View Model。
|
|
|
|
业务离线由本地 `obsidian-water-v1.riv` 的 `asleep` 状态播放内部缓慢水纹并关闭外围光圈,在线/离线切换保留同一实例。减少动态效果、加载和失败时显示从当前资源渲染的 `obsidian-water-idle.png` 或无光圈的 `obsidian-water-offline.png`。隐藏和减少动态效果会卸载实例,不通过 CSS 同时隐藏多个仍运行的 Persona。资源改造见 [Agent 动画资源说明](../agent-persona-design.md#8-资源生成与维护)。`hover` 输入由外层交互控制,Rive 自带的 DOM 监听关闭,避免和原生入口按钮及触摸操作重复响应。
|
|
|
|
回归验证已覆盖原始字节缓存、失败后的重试、无 View Model 绑定、原生状态及 hover 切换、真实 canvas 动画和桌面/手机单实例。
|
|
|
|
独立原版 / 接入版预览进行了 35 秒浏览器渲染进程 RSS 观察:约 193.3 MiB 至 177.2 MiB,未观察到持续增长。该结果仅覆盖本地短时对照预览;本轮没有重新引入 View Model 绑定,也未更新 Rive 版本。
|