【问题标题】:Does this simple js code has memory leak?这个简单的js代码有内存泄漏吗?
【发布时间】:2013-03-09 15:39:27
【问题描述】:

我有一个简单的 html/javascript 代码,它将创建一些 DOM,然后删除它们。

<!DOCTYPE html>
<html>

  <head lang="en">
    <meta charset="utf-8">
    <title>Custom Plunker</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  </head>

  <body>
    <button onclick="create()"> Create </button>
    <button onclick="clearContainer()"> Clear </button>

    <div id="container"></div>

  </body>

</html>

<script>
  function create() {
    var c = $("#container");
    for(var i = 0;i<10000; i++){
    c.append("<li>Hellosd fssd f df sdf  f f wef ewf we fwe f wef ewf wef ew few f ewf wf ewf wef </li>");
    }
  }

  function clearContainer() {
    var c = $("#container");
    c.empty();
  }
</script>

会有一个Create 按钮和一个Clear 按钮。当我单击创建按钮时,它会将 10000 li 元素附加到容器 div 中,当我单击清除按钮时,它将删除它们。

当我在chrome上尝试时,chrome进程初始内存使用量约为30M,在我点击创建按钮几次后增长到70M,当我点击清除按钮时,它变成了50M。比初始多 20M。

然后我在IE8上试了一下,IE进程初始内存占用30M左右,我只点击一次create按钮后就增长到100M以上,点击clear按钮后就变成了80M。比最初多了 50M。

代码是否有内存泄漏?如何解决?

【问题讨论】:

  • 您是以某种方式测量实际数据使用量还是测量(更有可能)保留的内存,这将超过实际使用的数据?
  • 这里有一个fiddle 来查看它的实际效果。

标签: javascript memory-leaks


【解决方案1】:

代码是否有内存泄漏?

没有。浏览器只是保留他们分配的一些内存,以防他们需要重用它,和/或还没有(还)垃圾收集不再引用的对象。因为您已经发布了对列表项元素的所有引用(通过 jQuery 的 empty 调用),所以要让浏览器真正放开它们。

当然,此答案假定您调用的 jQuery 函数中没有导致内存泄漏的错误(尤其是创建 li 元素的错误)。这可能是一个合理的假设,当然,即使是受人尊敬的图书馆偶尔也会出现错误。如果 jQuery 的一个常用功能(包括元素构造)在给定版本中存在严重的内存泄漏,那么考虑到使用该库的人数和背后的参与团队,它很可能会在合理的时间内被发现、报告和修复它。

我们还假设浏览器在处理 DOM 操作时没有错误导致内存泄漏,这是一个不太确定的假设。 (从历史上看,浏览器 [无论哪种风格] 都会遇到各种内存泄漏问题;我认为 任何 浏览器都无法幸免。)

如果您明白我的意思,您的代码中没有泄漏。

【讨论】:

  • 你确定吗?我测试了 OP 的代码,在每次创建/清除后,占用的内存更重要了大约 5 到 10 MB。
  • @dystroy:您可以肯定地看到该代码。 OP 没有保留对 li 元素的任何引用,因此 OP 的代码不是内存泄漏的原因。正如我所说,OP 正在调用的 jQuery 函数之一总是可能存在一个,但更有可能只是内存流失。
  • 在 OS X 上的 Firefox 19 在第一次 create/clear 之后“保持”大约 30MB,并在每个新回合后回落到这个数量。
  • @insertusernamehere:你去吧,如果它在第一次通过后一直回落到相同的数量,这表明你没有导致内存泄漏。 Firefox(以占用内存而闻名)可能会在它保留的第一次传递中分配一些内部结构,或者至少分配一些不太容易识别为未引用的内存,因此 GC 不会那么快。跨度>
【解决方案2】:

通过在 Chromium/linux 上进行测试,我可靠地重现了您的泄漏:每个创建/清除周期都会使内存增长 5MB 到 10MB,而这块内存似乎没有被释放。

我注意到可以通过稍微改变 clear 函数来替换父元素而不是清空它来避免泄漏:

  function clearContainer() {
    var c = $("#container");
    c.remove();
    $('<ul id="container"></ul>').appendTo(document.body);
  }

使用此代码,每次创建/清除周期后内存都会恢复到相同的水平。

我不认为问题出在 jQuery 中,但更有可能是浏览器的 DOM 对象,因为 Firefox 似乎没有同样的问题。


编辑

通过自动化测试以将其推得更远,我可以看到内存最终减少(我的选项卡最高约为 150 MB,然后可能会回到 70 MB)。这里管理内存的方式显然是贪婪的,但没有真正的内存泄漏。由于内存消耗可能如此不同,我建议您删除父元素而不是清除它,但这不会防止任何崩溃,因为内存崩溃似乎不太可能。

【讨论】:

  • +1 表示努力和改变。 “...而且这个内存永远不会被释放。” 你等了多久/你试图看到这是什么永远释放?你一直坚持到发生什么事情吗?这是“内存泄漏”的黄金标准(以及您几乎必须做的事情,将其报告为 Chromium 中的错误)。 (我并不是说这不是一个有趣的结果,只是它不一定是 泄漏。而且它显然不是 OP 的代码中的泄漏。)
  • @T.J.Crowder 在我 5 百万前的最后一次测试之后,内存没有改变。它仍然是 136 MB,而我的其他清理功能会立即释放内存。
  • @dystroy:五分钟不是“永远”。同样,你必须推动它直到有东西破裂才能称之为泄漏。否则,您只是不知道 GC 在内部做什么。 GC 复杂
  • @dystroy:不错的分析,如果可以的话再+1。 :-)
猜你喜欢
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 2012-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
相关资源
最近更新 更多