Javascript 闭包是如何产生内存泄漏的?

Javascript 闭包是如何产生内存泄漏的?,javascript,Javascript,我正在回顾本演示文稿中的幻灯片: 在其中一张幻灯片上,这段代码提示它会造成内存泄漏: var a = function () { var smallStr = 'x', largeStr = new Array(1000000).join('x'); return function (n) { eval(''); //maintains reference to largeStr return smallStr; }; }();

我正在回顾本演示文稿中的幻灯片:

在其中一张幻灯片上,这段代码提示它会造成内存泄漏:

var a = function () { 
   var smallStr = 'x',
   largeStr = new Array(1000000).join('x'); 

   return function (n) { 
        eval(''); //maintains reference to largeStr
        return smallStr; 
   }; 
}();
闭包可能是内存泄漏的另一个来源。了解闭包中保留了哪些引用

记住:eval是邪恶的


有人能解释一下这个问题吗var a = (function () { // `a` will be set to the return of this function var smallStr = 'x', largeStr = new Array(1000000).join('x'); return function (n) { // which is another function; creating a closure eval(''); return smallStr; }; }()); 内部函数需要能够访问外部函数中的所有变量,这意味着只要存在对外部函数的引用,外部函数中的变量就不能被垃圾收集,从而在完成调用后继续消耗内存,因此可能导致“内存泄漏”


如果您正在处理这样的大数据,并且已经完成了处理,请将其设置为
null

If,而不是返回一个函数

    eval('');
您返回了一个通过其论点的

    eval(n);
然后有人可以调用
a('largester')
来获取数组,这样JavaScript解释器就不能对数组进行垃圾收集

口译员可以意识到这一点

eval('');
相当于

;
但大多数人都不太聪明,所以一旦他们看到
eval
,他们就停止允许GC关闭变量,只要可以访问闭包


由于输入的性质,
eval
无法有效访问闭合变量时,会出现内存泄漏:

eval('x' + (n-1));
由于
'x'+(n-1)
无法生成引用
最大值的JS字符串,因此没有任何输入可以导致使用
最大值的JS,但它仍然固定在内存中


要看到整个事情的进展,请与

 var f = (function () {
     var a = [,,,,,];
     return function (x) { return eval(x); };
   })();
 alert(f('a.length'));

让我们稍微重写一下代码:

function makeClosure() { 
  var smallStr = 'x',
  largeStr = new Array(1000000).join('x'); 

   return function (n) { 
        eval(''); //maintains reference to largeStr
       return smallStr; 
  }; 
}

var a = makeClosure();
assert(a() === 'x');
makeClosure
返回一个函数,因此
a
是一个函数。但是,该函数仍然在定义它的范围内执行(这是闭包的定义)。如果你要做:

function makeEnumerator() {
  var count = 0;

  return function () {
    count++;
    return count;
  };
}

var enum = makeEnumerator();
assert(enum() === 1);
assert(enum() === 2);
enum
仍然可以访问
count
。回到我们的例子,闭包保留了对
smallStr
的引用,该引用保留在内存中<代码>最大值
未保留,应释放

但是,
eval
也在当前作用域中执行,并且可能使用更大的
。正因为如此,浏览器也被迫保持
最大


长话短说,不要使用eval:)

我不认为这是同一演示文稿定义的内存泄漏(该演示文稿说,泄漏是“当程序多次未能返回为临时使用而获得的内存时”),因为它不会重复发生。但是,
larger
将占用大量内存,直到
a
超出范围。另外,
eval()
也不是邪恶的,它几乎总是这个工作的错误工具。@nnnnnn:尤其是在这里,
eval
似乎被用来阻止静态代码分析,这样即使在对返回函数的引用处于活动状态时,垃圾收集器也可以收集
largester
。@MedicineMan:你知道吗“理解闭包中保留了哪些引用”与否?@Bergi-因此,在这种情况下,如果作业有意占用内存,则
eval()
是正确的作业工具。(只要人们理解课程是“小心闭包”,而不是“
eval()
总是占用内存”。)@nnnnnn:我担心,这是很多人会做的。最好用
if(false)return largester;
这样的解释来代替它。这是一个很好的解释,对任何阅读你的答案感兴趣的人来说都应该是不言自明的。@Bergi,我纠正了这个错误。谢谢。