JavaScript垃圾回收器不会回收setTimeout()吗?

4

我有一个函数:

function test()
{
            for( var i = 0; i < 1000000; i++ )
            {
                setTimeout( function()
                {
                    //
                }, 10000 );
            }
}

在Chrome上运行此操作,它会将内存使用量从大约50MB增加到600MB,我想这是可以接受的;但在超时已执行后,垃圾收集器似乎没有将它们从内存中删除,它仍然停留在600MB直到我刷新,即使在刷新页面后仍然留下了一些150MB的“足迹”。
有没有办法告诉垃圾收集器在执行后立即清除它们?

2
用那么少的代码将内存使用量从50MB增加到600MB是不可接受的。你正在创建一百万个新计时器。 - slasky
1
请查看https://dev59.com/iV3Va4cB1Zd3GeqPA3px#8217000。 - Daniel Lizik
在https://jsfiddle.net/barmar/ntjhrz6u/1/上创建了一个小工具。在Chrome中,它没有达到600MB,只有大约100MB。但即使我等待了大约10秒钟,它也没有自动清理。 - Barmar
@Bergi 哦,我明白了;嗯,看着 JavaScript 的内存,它似乎没有太多变化,大约保持在 11,600K 左右(6,900K 实时)。 - Dmytro Lysak
您所展示的代码中没有节点。您确定这是您要测试的内容吗? - Bergi
显示剩余10条评论
1个回答

0

你说得对,似乎有一些内存没有被清理。我猜测问题可能是在像这样的for循环中创建函数会创建一个新的作用域,该作用域必须访问i。因此,这些函数永远不会被清理。我说错了 - 这些函数肯定会被清理。在我的浏览器中测试,内存使用量超过了900MB。

需要注意的是,这样做没有任何好处,最多只能算是“糟糕的代码”。你应该创建一个函数并重复使用它:

// reusing a function fixes the problem
function test () {
    var fn = function () {};
    for (var i = 0; i < 1000000; i++) {
        setTimeout(fn, 1000);
    }
}

我的观察是,内存使用量迅速上升到900MB以上,然后在几分钟内逐渐回落到接近正常水平。

如果您需要在函数内部访问变量i,我很抱歉告诉您,您的代码将无法实现。您只能看到i的最后一个值(1000000)。如果您想在函数内部使用i,可以使用工厂函数。在我的测试中,内存最终被清理:

// using a factory fixes the problem and give you access to 'i'
function test () {
    function factory (n) {
        return function () {
            /* This will get called later. 'n' will represent
               the value of 'i' at the time this function was created */
        }
    }
    for (var i = 0; i < 1000000; i++) {
        setTimeout(factory(i), 1000);
    }
};

不幸的是,如果您使用bind,内存问题仍然存在:

// Memory problem still exists with .bind
function test () {
    var fn = function (n) { };
    for (var i = 0; i < 1000000; i++) {
        setTimeout(fn.bind(null, i), 1000);
    }
}

关于页面刷新后内存使用仍然很高,我无法解释,但可能与浏览器为正在使用大量内存的选项卡保留更多内存有关。我不知道,只是猜测而已。

“因此,这些函数永远不会被清除” - 我不明白。每个函数被调用并创建了其作用域之后,就没有什么可以保留的了? - Bergi
这很令人困惑,显然如果我使用 "setTimeout(fn, 1000);" 那么它就能工作,但如果我使用 "setTimeout( fn, 1000 );" 那么它就不能工作? - Dmytro Lysak
@bergi - 谢谢 - 我刚才对问题的理解有误。我已经更新了我的答案。 - Ryan Wheale
1
@DmytroLysak - 我不太清楚你的意思。在 setTimeout 调用内部使用空格会导致内存问题吗?我很难相信这一点。你可以创建一个演示给我看吗? - Ryan Wheale
你正在使用的是什么工厂东西?为什么test()函数外面有括号? - Dmytro Lysak
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接