JavaScript 内存泄漏入门指南
在本文中,我将采用一种非常简单的方法来理解内存泄漏,并且我还将尝试对其进行诊断。
在如今内存充裕的世界里,我们很少会担心内存泄漏。但我不得不说,我们生活在一个现实社会,没有什么东西是免费的。
哦,我喜欢函数式编程
声明:我超爱函数式编程。
函数式编程本身就很酷,有了新的 ES6 语法,就更酷了。
const arrayAddFirst = (a, b) => [a, ...b];
上面这个例子看起来太棒了。除非你跟我一起写程序,然后我盲目地把它放进一个重载循环里😎。
result = newData.reduce((p,r) => arrayAddFirst(r, p), []);
现在我不想让你因为上面的愚蠢代码而评判我。(如果你能猜出它的作用,就给我一个虚拟拥抱😁)
for(var i = 0; i < newData.length; i++) {
for(var j = 0; j < i; i++) {
// stuff here
}
}
上面的代码片段是我们示例的旧版等价版本。注意,很容易看出它的运行n * (n+1) / 2
时间,其中n
的长度是newData
。
示例代码的主要问题是垃圾收集器必须频繁启动。[a, ...b]
每次循环中创建的数组.reduce
都需要从内存中删除,否则它最终会占用所有内存。
这个例子试图阐明一个重要的事实:记忆并非你最好的朋友。它99%的时间对你有利,但当它决定刺你时,它会直接刺中你的眼睛。
内存泄漏...
通常,JavaScript 应用程序会以两种方式冻结:
无限循环:您可能意外地编写了一个永不终止的循环。
var x = 0;
while(x < 5) {
console.log(x); // Warning! do not try this at home
}
内存不足:我们都知道计算机的内存是有限的,如果我们不小心,可能会占用所有的内存。
var x = [ [1] ];
for(var i = 1; i < 100000; i++) {
x.push(arrayAddFirst(i, x[i-1])); // Warning! do not try this at home
}
好吧,但是内存泄漏怎么办呢?
当然,只要小心谨慎,你就能轻松避免这些不良行为。但内存泄漏就像那些默默潜伏的讨厌鬼一样。
让我们定义一台拥有无限资源的计算机,并将其命名为。我们将在本文中Deep thought
引用,您很快就会看到我们将如何使用它来找出内存泄漏。Deep thought
DT-42
DT-42
内存泄漏
简单来说,内存泄漏就是被遗忘的数据,永远等待被使用。
在我们深入探讨其科学定义之前,先来看一个例子。
function sayHi() {
var allNames = [];
var emoji = '👋';
return name => {
allNames.push(name);
return emoji + name;
}
}
在示例中,我们的程序每次调用都会变得越来越臃肿。垃圾收集器无法清理,allNames
因为函数需要它来推送数据。它无法确定 allNames 永远不会被读取,因此给它任何内存空间都是徒劳的。
维基百科说:
我觉得把它想象成一种症状更容易理解。你的程序就是一个病人,它对记忆的热爱会无限增长。

大多数时候,计算机(垃圾收集器)足以识别出你不再使用的大部分数据,并为你清理干净。但它并不完美,而且我们还远没有找到比人类更聪明的垃圾收集器。(如果我们真的有这样的垃圾收集器,那它应该是写代码的人,而不是我们自己 :P)
给我一些现实生活中的泄漏
现实生活中的问题在于,我们很少遇到这种微不足道的内存泄漏,大多数情况下,泄漏都潜伏在看似运行良好的代码片段(比如arrayAddFirst
)。与其抛出一些现实生活中的泄漏案例,我更愿意教你如何识别内存泄漏。
让我们启动 Chrome 来帮助诊断内存泄漏。
- 打开一个空白页。
- 打开开发面板(Command+Option+I 或 Control+Shift+I)
- 将此示例代码粘贴到控制台中。
function sayHi() {
var allNames = [];
return name => {
allNames.push(name);
return '👋 ' + name;
}
}
var hello = sayHi();
hello('Gandhi');
好的,我们已经开始泄漏内存,现在让我们打开我们的memory profiler
。
您应该能够memory
在开发工具中找到它作为一个选项卡。
就本文而言,我们将重点介绍Take Heap Snapshot
。此功能会拍摄程序当前内存使用情况的快照。
就我而言,它看起来像这样:
太好了,现在我们将运行几次看似无害的功能。
for(var i=0; i<1000000; i++) {
hello('Gandhi');
}
如果您拍摄另一个快照,您将看到内存使用量增加。
就我的情况而言,差异高达10MB。在很多实际情况下,几MB 的跳跃可能是正常的,你可能需要一段时间内拍摄多张快照来排除内存泄漏的可能性。
您可以通过单击Summary
下拉菜单并切换到轻松比较两个快照Comparison
。
如果你将新的快照与之前拍摄的快照进行比较,并将其#Delta
降序排列,你会发现 中有一个很大的数字(string)
。这就是内存泄漏的地方。点击它,你会看到很多Gandhi
。
我真心希望这篇文章能帮助你理解内存。这只是诊断内存泄漏的几种方法之一。请查看以下链接,了解更多有关内存的高级见解:
如果您❤️这篇文章,请分享这篇文章来传播。
文章来源:https://dev.to/kepta/a-toddlers-guide-to-memory-leaks-in-javascript-25lf