Catching memory leaks with Chrome DevTools
当调配的内存没有返回给操作系统或内存池时,咱们将其称为内存透露。在这种状况下,内存未被任何应用程序应用,并且被不必要地占用。这会导致低性能、高提早和频繁解体。
Understanding memory leaks
如果您相熟 C 等低级语言,您肯定应用过 malloc() 和 free()。相比之下,JavaScript 在创建对象时主动分配内存,并在不再应用时开释它。
好吧,因为它是主动治理的,所以咱们作为开发人员总是有一个谬误的印象,即咱们不须要放心浏览器中的内存治理。如果一个站点应用越来越多的内存,这意味着没有人收集它并且存在内存透露。
Garbage collectors
如果垃圾收集器 (GC) 是完满的,那么内存透露就不是问题。问题是他们的算法不够聪慧,无奈检测内存透露。因而,须要人工干预。
垃圾收集器执行查找程序不再应用的内存并将其开释回操作系统以供未来重新分配的过程。该办法无效,但依然会产生内存透露。该办法无奈检测每个透露,例如透露的援用。
Why is there a memory leak?
下列是几种常见的内存透露类型。
Accidental global variables
function getWork() {this.work =“I am Memory leak”;}
// The this here refers to window object and hence this variable will be created in the window.
getWork();
这里的 this 指的是 window 对象,因而这个变量将在 window 中创立。
因为全局变量不是由 GC 收集的,如果此字符串变得太大,可能会导致内存透露。意外全局变量的一个相似示例是在不应用 let 和 var 关键字的状况下申明变量。
Detached DOM nodes
拆散 DOM 节点是一个关键问题。因为全局援用,拆散的节点依然存在于内存中。
var node = document.createElement(‘a’);
node.id = 'id1';
document.body.appendChild(node);
var main = {Id: document.getElementById(‘id1’)
}
function removeElement(){document.body.removeChild(document.getElementById(‘id1’));
}
removeElement();
在下面的例子中,removeChild 函数从树中移除了 DOM 节点,然而全局主对象中的援用 Id 依然保留在内存中并且没有被垃圾收集。
闭包
闭包为外部函数保护内部函数变量的范畴,即便在内部函数的范畴之外。
function getScore(x) {function score(y) {return x + y;}
return score;
}
var initial = getScore(2);
var final = initial(3);
这里的函数 score,也就是外部函数,有一个全局援用,叫做 initial。这个初始援用永远不会被垃圾收集。
Tools to identify memory leaks
意外的全局变量 内存透露能够通过剖析轻松检测到。咱们举一个代码片段的例子,它会因为全局变量而导致内存透露。
例子:
var x = []
var bool = false;
function grow(){x.push(new Array(100000).join(‘a’));
if(bool){setTimeout(grow, 1000);
}
}
function start(){grow();
bool = true;
}
function stop(){bool = false;}
到 Chrome 开发者工具里,关上 Profiles 标签页:
抉择 Take Heap Snapshot.
在这里,window 对象的黄色实际上描述了从 JS 代码中间接援用的节点。咱们须要修复这里的代码,以便咱们能够解脱黄色标记。
此处的选项是在函数内将数组设为部分,以便垃圾收集器能够收集它或显式删除全局变量。您能够找到更正后的代码:
var bool = false;
function grow(){var x = [];
x.push(new Array(100000).join(‘a’));
if(bool){setTimeout(grow, 1000);
}
}
function start(){grow();
bool = true;
}
function stop(){bool = false;}
Allocation profiler
Allocation Timeline 是另一个工具,能够帮忙您跟踪 JS 堆中的内存透露。要记录时间线,请转到您的 profile 面板,而后单击下面给出的雷同代码的开始。
当咱们单击如图所示的开始按钮并应用调配分析器进行配置时,咱们能够看到它生成了如图所示的蓝线。
蓝条代表新的内存调配,这可能是内存透露。您能够通过缩放这些蓝色条中的任何一个来查看详细信息。此处的详细信息示意被推入数组且从不进行垃圾回收的长字符串。
更多 Jerry 的原创文章,尽在:” 汪子熙 ”: