Chrome 浏览器垃圾回收机制与内存泄漏分析 (3)

只有页面的 DOM 树或 JavaScript 代码不再引用 DOM 节点时,DOM 节点才会被作为垃圾进行回收。 如果某个节点已从 DOM 树移除,但某些 JavaScript 仍然引用它,我们称此节点为“已分离”,已分离的 DOM 节点是内存泄漏的常见原因。

同理,调出调试面板,点击Memory,然后选择Heap Snapshot,然后点击进行录制。录制完成后,选中录制结果,在 Class filter 文本框中键入 Detached,搜索已分离的 DOM 树。
以这段代码为例:

<html> <head> </head> <body> <button>增加节点</button> <script> var detachedNodes; function create() { var ul = document.createElement('ul'); for (var i = 0; i < 10; i++) { var li = document.createElement('li'); ul.appendChild(li); } detachedTree = ul; } document.getElementById('createBtn').addEventListener('click', create); </script> </body> </html>

点击几下,然后记录。可以得到以下信息:

GitHub


旧版的面板,还会有颜色标注,黄色的对象实例表示它被JS代码引用,红色的对象实例表示被黄色节点引用的游离节点。上图是新版本的,不会有颜色标识。但是还是可以一个个来看,如上图,点开节点,可以看到下面的引用信息,上面可以看出,有个HTMLUListElement(ul节点)被window.detachedNodes引用。再结合代码,原来是没有加var/let/const声明,导致其成了全局变量,所以DOM无法释放。

按函数调查内存分配
打开面板,点击JavaScript Profiler,如果没看到这个选项,你可以点调试面板右上角的三个点,选择more tools,然后选择。

ps: chrome 旧版的浏览器,这个功能在 Profiles 里面,点Record Allocation Profile即可.

操作步骤:点start->在页面进行你要检测的操作->点stop。

GitHub


DevTools 按函数显示内存分配明细。默认视图为 Heavy (Bottom Up),将分配了最多内存的函数显示在最上方,还有函数的位置,你可以看看是哪些函数占用内存较多。

避免内存泄漏的方法

少用全局变量,避免意外产生全局变量

使用闭包要及时注意,有Dom元素的引用要及时清理。

计时器里的回调没用的时候要记得销毁。

为了避免疏忽导致的遗忘,我们可以使用 WeakSet 和 WeakMap结构,它们对于值的引用都是不计入垃圾回收机制的,表示这是弱引用。
举个例子:

const wm = new WeakMap(); const element = document.getElementById('example'); wm.set(element, 'some information'); wm.get(element) // "some information"

这种情况下,一旦消除对该节点的引用,它占用的内存就会被垃圾回收机制释放。Weakmap 保存的这个键值对,也会自动消失。

基本上,如果你要往对象上添加数据,又不想干扰垃圾回收机制,就可以使用 WeakMap。

参考资料

极客时间《浏览器工作原理与实践》

https://developers.google.com/web/tools/chrome-devtools/memory-problems?hl=zh-cn

最后

欢迎加我微信(winty230),拉你进技术群,长期交流学习...

欢迎关注「前端Q」,认真学前端,做个有专业的技术人...

GitHub

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgwxj.html