【前端】如何检查内存泄漏
在实际的场景中,如果观察到内存持续出现峰值,并且内存消耗一直没有减少,那可能存在内存泄漏。
使用 Chrome DevTools 来识别内存图和一些内存泄漏,我们需要关注以下两个方面:
● 使用性能分析器可视化内存消耗;
● 识别分离的 DOM 节点。
(1)使用性能分析器可视化内存消耗
以下面的代码为例,
<!DOCTYPE html>
<html lang="en"><head><title>Memory leaks</title></head><body><button id="print">打印</button><button id="clear">清除</button></body>
</html>
<script>var longArray = [];function print() {for (var i = 0; i < 10000; i++) {let paragraph = document.createElement("p");paragraph.innerHTML = i;document.body.appendChild(paragraph);}longArray.push(new Array(1000000).join("y"));}document.getElementById("print").addEventListener("click", print);document.getElementById("clear").addEventListener("click", () => {window.longArray = null;document.body.innerHTML = "Cleared";});
</script>
有两个按钮:打印和清除。点击“打印”按钮,通过创建 paragraph 节点并将大字符串设置到全局,将1到10000的数字追加到DOM中。
“清除”按钮会清除全局变量并覆盖 body 的正文,但不会删除单击“打印”时创建的节点
当每次点击打印按钮时,JavaScript Heap都会出现蓝色的峰值,并逐渐增加,这是因为JavaScript正在创建DOM节点并字符串添加到全局数组。当点击清除按钮时,JavaScript Heap就变得正常了。 除此之外,可以看到节点的数量(绿色的线)一直在增加,因为我们并没有删除这些节点。
(2)识别分离的 DOM 节点
当一个节点从 DOM 树中移除时,它被称为分离,但一些 JavaScript 代码仍然在引用它。让我们使用下面的代码片段检查分离的 DOM 节点。通过单击按钮,可以将列表元素添加到其父级中并将父级分配给全局变量。简单来说,全局变量保存着 DOM 引用。
var detachedElement;
function createList(){let ul = document.createElement("ul");for(let i = 0; i < 5; i++){ul.appendChild(document.createElement("li"));}detachedElement = ul;
}
document.getElementById("createList").addEventListener("click", createList);
使用 heap snapshot 来检查分离的DOM节点,可以在Chrome DevTools 的Memory面板中打开Heap snapshots选项:点击下面蓝色的Take snapshot按钮,我们可以在中间的搜索栏目输入Detached来过滤结果以找到分离的DOM节点,如下所示: