JavaScript垃圾收集这个吗?

时间:2012-11-20 15:30:58

标签: javascript garbage-collection

每隔一段时间我就会发现自己在做以下几点的事情。

var img = new Image();
img.src = 'php/getpic.php?z=' + imid + '&th=0';
img.onload = function(){drawImages(img,contexts,sizes)};

解释

  1. 创建HTML图像元素。
  2. 分配其src属性
  3. 分配其onload事件
  4. 将一个或多个Canvas上下文传递给事件处理程序
  5. 将加载的图像绘制到画布
  6. 我不清楚的是这个问题 - JavaScript垃圾收集器是否会处理丢弃img元素的任务,或者我是否需要自己执行此操作,否则会遇到缓慢的内存泄漏?

2 个答案:

答案 0 :(得分:7)

将在 IE 6和7 (以及非常旧版本的FF)中泄漏,因为它会在JavaScript和DOM之间创建循环引用。 IE 6和7不能垃圾收集任何在两个世界之间具有循环引用的对象,因为它们使用单​​独的垃圾收集器。

现代浏览器可以在不泄漏的情况下处理此问题。

为防止它在IE 6和7中泄露,请在完成img后执行此操作:

img.onload = null;

如果您只关心现代浏览器,则无需担心。 (我很高兴IE 6和7的市场份额最终足够低,以表明这一点!)


更新

您分配给onload的函数会创建一个闭包。该闭包包含对img的引用。只要JScript的内存中存在该闭包(JScript是JavaScript的IE实现的名称),就不能从DOM的内存中收集img。同样,只要img存在于DOM的内存中,就不能从JScript的内存中收集闭包,因为img.onload具有对您的函数的引用。这是一个循环参考。换句话说,仅仅因为drawImages执行一次并不意味着它不会再次执行(JScript引擎不知道onload只触发一次 - 这是DOM的域),所以JScript有保持封闭活着。

您所展示的模式是已知在IE 6和更高版本中创建内存泄漏的经典模式。 7.它由(1)一个DOM节点,(2)该DOM节点上的一个事件处理程序创建一个闭包,以及(3)一个返回该闭包内该DOM节点的引用。

答案 1 :(得分:6)

如果您担心内存泄漏,我建议您使用Heap Debugger of Google Chrome。在您的情况下,我做了一个简单的测试,可以验证您的特定模式是否会造成内存泄漏。

<html>
    <head>
        <script>
            function test() {
                var img = new Image();
                img.src = 'php/getpic.php?z=1&th=0';
                img.onload = function(){ drawImages(img,contexts,sizes); };
            }
        </script>
    </head>
    <body>
        <input type="button" onclick="test()" value="test" />
    </body>
</html>

我建议你在测试前按“test”一次,以避免在结果中产生不必要的噪音(在第一次代码运行时,内存中会添加一些东西,这并不意味着内存泄漏)。 / p>

获取堆快照,按test并获取堆快照。如果您想要实际结果,则必须将视图从“摘要”切换到"Comparaison"。如果视图为空(在我测试的情况下),则表示在该步骤期间未添加任何内容,这意味着它没有内存泄漏。在另一种情况下,它将显示快照之间添加或删除的内容。

注意:此方法无法帮助您解决具有自身问题的旧浏览器的内存泄漏问题,但这是在大多数现代浏览器中找到会导致内存泄漏的问题的一个很好的步骤。