内存泄露检查清单
复杂 Canvas 应用关闭页面后,内存不下降通常不是 canvas 绘制本身的问题,而是对象仍被引用。
页面关闭时必须释放
- 页面根 RenderObject。
- 页面 controller。
- 页面级 AppContext。
- 页面级 CommandScope。
- Popup、Modal、Window。
- 事件订阅。
- setTimeout / setInterval。
- Image 加载回调。
- 大数组、大文本、大文档模型。
- 业务缓存。
dispose 规则
组件持有可释放对象时,必须在 dispose() 中释放。
dispose():
dispose owned controller
remove event subscriptions
clear timers
close popups
call parent dispose
如果对象由外部传入,组件要明确是否拥有它。只有 ownsController 为 true 时才由组件释放 controller。
资源缓存
资源缓存应尽量挂到文档上下文或页面上下文,不要默认全局缓存。
适合页面级缓存:
- 当前文档图片。
- 当前文档条码计划。
- 当前页面查询结果。
- 当前页面临时对象。
适合全局缓存:
- 字体。
- 主题常量。
- 小型纯函数结果,并且有上限。
常见泄露来源
- PopupManager 仍持有关闭页面的 popup。
- Window owner/owned 关系没有解除。
- 全局事件监听没有 remove。
- Image.onload 闭包引用组件。
- 文档缓存挂在模块级 Map。
- AppContext 中放了大对象且没有 dispose。
验证流程
- 打开页面。
- 加载大数据。
- 关闭页面。
- 手动触发应用实例 dispose。
- 生成 heap snapshot。
- 搜索页面类名、文档 id、大数组关键字段。
- 查看 retainers,定位谁还持有对象。