JavaScript 内存泄漏入门指南

2025-06-07

JavaScript 内存泄漏入门指南

在本文中,我将采用一种非常简单的方法来理解内存泄漏,并且我还将尝试对其进行诊断。

在如今内存充裕的世界里,我们很少会担心内存泄漏。但我不得不说,我们生活在一个现实社会,没有什么东西是免费的。

哦,我喜欢函数式编程

声明:我超爱函数式编程。
函数式编程本身就很酷,有了新的 ES6 语法,就更酷了。

const arrayAddFirst = (a, b) => [a, ...b];
Enter fullscreen mode Exit fullscreen mode

上面这个例子看起来太棒了。除非你跟我一起写程序,然后我盲目地把它放进一个重载循环里😎。

result = newData.reduce((p,r) => arrayAddFirst(r, p), []); 
Enter fullscreen mode Exit fullscreen mode

现在我不想让你因为上面的愚蠢代码而评判我。(如果你能猜出它的作用,就给我一个虚拟拥抱😁)


for(var i = 0; i < newData.length; i++) {
    for(var j = 0; j < i; i++) {
        // stuff here
    }
}
Enter fullscreen mode Exit fullscreen mode

上面的代码片段是我们示例的旧版等价版本。注意,很容易看出它的运行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 
}
Enter fullscreen mode Exit fullscreen mode

内存不足:我们都知道计算机的内存是有限的,如果我们不小心,可能会占用所有的内存。

var x = [ [1] ];
for(var i = 1; i < 100000; i++) {
    x.push(arrayAddFirst(i, x[i-1])); // Warning! do not try this at home 
}
Enter fullscreen mode Exit fullscreen mode

好吧,但是内存泄漏怎么办呢?

当然,只要小心谨慎,你就能轻松避免这些不良行为。但内存泄漏就像那些默默潜伏的讨厌鬼一样。

让我们定义一台拥有无限资源的计算机,并将其命名为。我们将在本文中Deep thought引用,您很快就会看到我们将如何使用它来找出内存泄漏。Deep thoughtDT-42DT-42

内存泄漏

简单来说,内存泄漏就是被遗忘的数据,永远等待被使用。
在我们深入探讨其科学定义之前,先来看一个例子。


function sayHi() {
    var allNames = [];
    var emoji = '👋';
    return name => {
        allNames.push(name);
        return emoji + name;
        }
} 
Enter fullscreen mode Exit fullscreen mode

在示例中,我们的程序每次调用都会变得越来越臃肿。垃圾收集器无法清理,allNames因为函数需要它来推送数据。它无法确定 allNames 永远不会被读取,因此给它任何内存空间都是徒劳的。

维基百科说:

内存泄漏是一种资源泄漏,当计算机程序错误地管理内存分配[ 1]时,就会发生这种泄漏,从而导致不再需要的内存不会被释放。

我觉得把它想象成一种症状更容易理解。你的程序就是一个病人,它对记忆的热爱会无限增长。

爱

大多数时候,计算机(垃圾收集器)足以识别出你不再使用的大部分数据,并为你清理干净。但它并不完美,而且我们还远没有找到比人类更聪明的垃圾收集器。(如果我们真的有这样的垃圾收集器,那它应该是写代码的人,而不是我们自己 :P)

给我一些现实生活中的泄漏

现实生活中的问题在于,我们很少遇到这种微不足道的内存泄漏,大多数情况下,泄漏都潜伏在看似运行良好的代码片段(比如arrayAddFirst。与其抛出一些现实生活中的泄漏案例,我更愿意教你如何识别内存泄漏。

让我们启动 Chrome 来帮助诊断内存泄漏。

  1. 打开一个空白页。
  2. 打开开发面板(Command+Option+I 或 Control+Shift+I)
  3. 将此示例代码粘贴到控制台中。
function sayHi() {
    var allNames = [];
    return name => {
            allNames.push(name);
            return '👋 ' + name;
        }
}
var hello = sayHi();
hello('Gandhi');
Enter fullscreen mode Exit fullscreen mode

好的,我们已经开始泄漏内存,现在让我们打开我们的memory profiler

您应该能够memory在开发工具中找到它作为一个选项卡。

图像

就本文而言,我们将重点介绍Take Heap Snapshot。此功能会拍摄程序当前内存使用情况的快照。

就我而言,它看起来像这样:

图像

太好了,现在我们将运行几次看似无害的功能。

for(var i=0; i<1000000; i++) {
    hello('Gandhi');
}
Enter fullscreen mode Exit fullscreen mode

如果您拍摄另一个快照,您将看到内存使用量增加。

图像

就我的情况而言,差异高达10MB。在很多实际情况下,几MB 的跳跃可能是正常的,你可能需要一段时间内拍摄多张快照来排除内存泄漏的可能性。

您可以通过单击Summary下拉菜单并切换到轻松比较两个快照Comparison

图像

如果你将新的快照与之前拍摄的快照进行比较,并将其#Delta降序排列,你会发现 中有一个很大的数字(string)。这就是内存泄漏的地方。点击它,你会看到很多Gandhi

我真心希望这篇文章能帮助你理解内存。这只是诊断内存泄漏的几种方法之一。请查看以下链接,了解更多有关内存的高级见解:

如果您❤️这篇文章,请分享这篇文章来传播。

通过 Twitter @kushan2020联系我

文章来源:https://dev.to/kepta/a-toddlers-guide-to-memory-leaks-in-javascript-25lf
PREV
在哪里上传你的文件🗄以便通过链接使用它们🔗(JS、CSS、字体、图像)简介图像字体Javascript结束
NEXT
追求 PostgreSQL 性能