关闭未使用变量的内存泄漏

时间:2016-08-08 20:35:02

标签: javascript

我想了解在哪种情况下,没有进一步使用的变量存储在闭包中并导致内存泄漏。我最喜欢的结果是"没有",但似乎并非如此。

据我所知,一旦函数在另一个函数内声明,其内部[[scope]]被赋予其封装函数的LexicalEnvironment。此LexicalEnvironment在此时引用局部变量和整个范围链。这基本上包括函数可以访问的所有自由变量(根据我对lostechies, javascript closures explained的理解)。

这里出现了第一个问题:这应该意味着所有只要函数存在就可以达到这些变量。例如。以下应该已经泄漏:



function a() {
    let big = new Array(1000000).join('*'); //never accessed
    //function unused() { big; }
    return () => void 0;
}
 
let fstore = [];
function doesThisLeak() {
  for(let i = 0; i < 100; i++) fstore.push(a());
}

doesThisLeak();
&#13;
&#13;
&#13;

幸运的是,我的firefox似乎并非如此。我已经收到了几个解释为什么它不会泄漏,从#34;抖动是聪明的&#34; to&#34; LexicalEnvironment是一种记录类型,这意味着GC可以收集未使用的变量&#34;。我仍然不知道其中一个是否正确,这是否在所有现代运行时间都没有泄漏以及原因。

经过进一步的研究,我发现auth0, four types of leaks in javascript(遗憾的是,似乎没有跳转到的html id,相关的部分是&#34; 4:Closures&#34;)这显示了一种欺骗任何东西的方法聪明的事情是收集未使用的变量。在上面的片段中,当只是取消注释&#34;未使用的&#34;功能,我没有看到RAM使用率再次下降(已经注意到它可能是GC因为其他原因而没有运行。但是,到目前为止,我假设它泄漏。我也被告知这仅限于firefox ,但它似乎在chrome中产生类似的行为

这个例子(如果它确实做了我认为它做的事情),表明由于同一范围内的函数声明,完全未使用的变量可能会泄漏。

结束我的问题:

  1. 在上面的片段中,&#34; big&#34;是什么原因?收集(当&#34;未使用&#34;被评论时)并在所有现代运行时发生这种情况?
  2. 假设使用&#34;未使用&#34;功能没有评论泄漏,什么是避免这种意外泄漏的最佳做法?还有吗?我已经得到了null的所有局部变量的建议,这些变量在函数结束时没有进一步使用,但是,这看起来很荒谬。我担心使用临时变量进行预先计算和意外泄漏。
  3. PS:很难确定这个问题还没有在关于内存泄漏问题的丛林中被问到。

3 个答案:

答案 0 :(得分:7)

编译器可以检查返回函数的代码以查看它引用的自由变量,并且只需要将这些变量保存在闭包中,而不是整个LexicalEnvironment。您可以通过检查Javascript调试器中的闭包来看到这一点。

function a() {
  let big = new Array(1000000).join('*');
  let small = "abc"; // is accessed
  return (x) => small + x;
}

fun = a();
console.dir(fun);

function b() {
    let big = "pretend this is a really long string";
    function unused() { big; }
    return () => void 0;
}

fun = b();
console.dir(fun);

在调试器中展开第一个函数时,您会在small属性中看到Closure,但不会看到bigb()。不幸的是,Chrome编译器似乎不够聪明,无法检测何时在未返回的未使用函数中引用变量,因此不需要保存它,因此我们在{{1}中出现泄漏}。

enter image description here

任何未保存在闭包中的数据都会变成垃圾并且可以被收集,因此它不会泄漏。

答案 1 :(得分:3)

致电a()后,您的fstore仅参考了已创建的功能() => voida()返回后,其范围变量将被删除。这意味着没有vars引用您的new Array(1000000).join('*')并且它将被垃圾收集。如果取消注释unused函数,它将以相同的方式收集,因为它也将被删除。您的代码中没有泄漏。

答案 2 :(得分:0)

pic1

您可以考虑存在问题的Javascript范围链,确定一个函数将创建一个新的范围链,如果函数的局部范围没有局部变量,它将引用词汇环境范围之外,并将其保留在内存中< / p>

这是link