您的位置:首页 > Web前端 > JavaScript

用 Chrome 开发者工具分析 javascript 的内存回收(GC)

2017-01-04 21:27 441 查看
今天在知乎看到一个问题:"通过 createElment 创建的元素,不 append 到 html 中,那么此元素被自动销毁的时机是什么?"
比如:

var a;

(function(){

   a = document.createElment("div");

})();


a = "Hello";


此时浏览器能否正确销毁和回收这个没有被 append 到页面上 dom 元素?
如果此元素不会被主动销毁或者回收,那么通过什么方法将其销毁呢?
我们知道,这种通过 document.createElment 创建出来的元素,是没有 parentNode 的,因为它创建时候并没有被添加到页面中。那么如何才能销毁它?
对 javascript 内存模型有了解的同学一定对下面的图很熟悉



当一个对象占用(使用)内存时,使用两种方式:直接和间接。直接占用内存很容易理解,而间接占用内存指对象中保持了对其它对象的引用,这样垃圾回收(GC 机制)就无法对那些对象进行回收。
在 GC 中一个很重要的概念就是 GC 根(GC root),当 javascript 程序中的某一个对象无法从 GC root 遍历到时,这个对象使用的内存就会被回收。
如下图的 9 和 10 就会被回收:



那么我们从原理角度分析一下最上面的代码,当执行 document.createElment("div") 时创建了一个 div 的 dom 对象,并赋值给了 a 变量,随后又把一个字符串 "Hello" 赋值给了 a 变量。此时 a 的值是 "Hello",类型是字符串。而之前创建的 div 对象已经不能通过 GC 遍历到,因此 div 对象被回收了。如果 div 对象没有被回收的话,我们观察如上代码,这个对象已经无法被任何变量所引用,因此就会产生内存泄漏。
下面我们通过使用 Chrome 的开发者工具分析一下如上代码。
首先新建一个空白 html 页面,页面里面什么代码也不写。
为了防止干扰,在 chrome 中新建一个隐身窗口,在隐身窗口中打开这个空白页面。
按 F12 或者 Ctrl + Shift + I,调出 devtools,选中 Profile 面板。



这时会记录此刻的内存使用情况



按 ESC 打开 Console,或者手动切换到 Console 面板,输入

var a;

(function(){

   a = document.createElment("div");

})();


然后按 Ctrl + E,或者再次点击 Take Heap Snapshot 按钮,这时又会记录一个 Snapshot2,选择 Comparison,可以将本次内存和上次记录的进行对比。
差异比较多,好多可以不用管,看最后一个:



选中之后下面有详细:



Detached DOM 的意思是这个 DOM 是游离在页面 DOM 之外的。
运行代码

a = "Hello";


继续上面的步骤后,Snapshot3 和 Snapshot2 相比,DOM 被 Delete 了:



Snapshot3 和 Snapshot1 相比,多了字符串 "Hello":



而通过 Heap Allocation Timeline 可以观察到 DOM 到底在什么时候被 GC 的。
欢迎关注我的公众号,长按图片识别二维码

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: