首页 > 代码库 > 一个JS内存泄露实例分析

一个JS内存泄露实例分析

在看JS GC 相关的文章时,好几次看到了下面这个设计出来的例子,比较巧妙,环环相扣。
 
var theThing = null;
var replaceThing = function () {
    var originalThing = theThing;
    var unused = function () {
        if (originalThing)
            console.log("hi");
    };
    theThing = {
        longStr: new Array(10000).join(‘*‘),
        someMethod: function () {
            console.log(1111);
        }
    };
};
 
setInterval(replaceThing, 1000);

 

由于 V8 GC 的关键是 root 级对象,因此内存泄露基本上都是由于 root 级引用没有被释放导致的。
 
上面代码中的 root 主要有两个,一个是 theThing,另一个是 replaceThing 运行时的调用栈。这里的内存泄露主要是 theThing。
 
总体来说是因为,root 级对象 theThing 持有了 replaceThing1 内部对象的引用,并且在下一次把引用转交给了 replaceThing2,然后持有了 replaceThing2 的内部引用。
详细一点:theThing 持有了 longStr 和 someMethod 的引用,由于 someMethod 这个闭包会保留它的 context,因此 replaceThing 整体被保留了,于是 unused 被保留;而 unused 又持有了 originalThing 的引用,因此 originalThing 持有了 由 theThing 转交过来的前一个 setInterval 时的 someMethod 和 longStr。 一次又一次 setInterval 下去,longStr 和 someMethod 就被串了起来。
 
图解:
 
setInterval1:
 
  originalThing           theThing
           |                           |
         null             someMethod1
 
 
setInterval2:
 
  originalThing           theThing
          |                            |
someMethod1    someMethod2   --unused--> replaceThing1 --> someMethod1
 
 
技术分享
 
 
 
 
 
 
 
 
 
 

一个JS内存泄露实例分析