查找 js 的内存泄漏, 这并不是真正的泄漏, 只是我们不需要了但还是一直被引用住了. 不想 c/c++ 那样 alloc 了一块内存并用指针指向它, 切断了这个指针就无法找到这块内存, 这才是真正的泄漏.
打快照前, 会自动执行gc.
控制台中打印一些对象时, 会导致引用住对象, 快照数据中会存在此对象的数据, 会 误认为泄漏, 以此, 打快照时最好清一下控制台信息, 以保证快照信息的准确性.
console.log(Object)
也会引用对象, 在 Chrome 中调试工具中 会出现 DevTools 字样.
打两个快照, 比如打开 n个ui 前, 打一个快照 s1, 打开 n个ui并关闭 后, 再大一个快照 s3, 使用快照 s3 对比 s1, 搜索对应ui 类名看是否存在, 如果存在则说明泄漏了
查找引用链
1 是 泄漏的类, 展开后是 泄漏的实例对象a , 后面有个 @2886161 是实例的唯一id
2 是这个实例对象a 被那些字段引用住了. 这里我用一个全局变量 gRef1 故意引用住了
ps: 按顺序查找, 后面的引用可能是 前面的引用造成的, 所以优先前面的引用, 如 gRef1. 解决完后 重新测一下, 后面的引用可能就不存在了.
比如使用观察者模式, 有个事件中心, 对象a 去事件中心注册了 事件b, 但是忘了反注册 事件b, 就会造成 对象a 一直被事件中心 给引用住.
回调泄漏也是容易查找的, 引用链中可以看到回调的一些参数, 很容易定位 问题代码在哪里.
可以看到被一个回调引用住了, 并且这个回调函数有个参数 event, 还可以跳转到对应的 js 查看具体的函数名
gEventCenter.on(Events.RefreshBagUI, this.onRefreshBagUI, this);
// gEventCenter.off(Events.RefreshBagUI, this.onRefreshBagUI, this); // 这里我是故意注释掉反注册
es6 标准中提供了一个 弱引用表 WeakMap, key是需要检测的对象, value: any. 重复的实例对象 set 进去, 只会保留最后一个. 奇怪的是这个表 可以直接通过 Chrome 控制太打印, 但是没有提供运行时遍历表的方法, 所以无法写工具 实时显示检测对象, 必须手动控制台打印该表对象.
一定要在浏览器上执行几遍 gc, 弱引用表内的数据才真实有效
导出内存数据, 防止内存堆积导致卡顿问题.
仅仅适用于web上浏览器打开操作. 都使用 Chrome 浏览器跑吧
玩游戏时, 时不时执行以下操作, 导出数据.
游戏时长越久, 数据越好. (能所有 UI 跑两边以上遍 及 跳多几次场景 是最好的)
按 F12 打开调试栏. 点三次 垃圾桶 (这一步很重要, 执行 gc操作)
输入指令. DebugMgr.instance._objMap
, 然后按 回车
展开所有小箭头, 复制所有数据 (复制到最底下就对了)
将 复制结果 丢到一个 新建文件. 每次导出顺序递增命名. 如 (1.txt, 2.txt, 3.txt … 等等), 打包发给 客户端