var theThing = nullvar replaceThing = function () { var originalThing = theThing var unused = function () { if (originalThing) console.log("hi") } theThing = { longStr: new Array(1000000).join('*'), someMethod: function () { console.log('someMessage') } };};setInterval(replaceThing, 1);`描述问题:这是nodejs中一个典型的垃圾回收案例,上面那段代码运行之后会带来非常明显的内存泄露情况,问题在于这段代码并没有形成闭包,为什么堆内的对象没有被立即释放?原文中的一个解释是unused函数内部引用了originalThing,但是函数运行之后,申请的内存就会被释放,原本指向unused的函数的指针也就没有了,所以unused函数在堆中也应该会被回收,对originalThing的引用也就不存在了,那么怎么会引起内存泄露呢?
1 回答
达令说
TA贡献1821条经验 获得超6个赞
这段代码做了一件事:每次调用 replaceThing 时,theThing 都会得到新的包含一个大数组和新的闭包(someMethod)的对象。同时,没有用到的那个变量持有一个引用了 originalThing(replaceThing 调用之前的 theThing)闭包。关键的问题是每当在同一个父作用域下创建闭包作用域的时候,这个作用域是被共享的。在这种情况下,someMethod 的闭包作用域和 unused 的作用域是共享的。unused 持有一个 originalThing 的引用。尽管 unused 从来没有被使用过,someMethod 可以在 theThing 之外被访问。而且 someMethod 和 unused 共享了闭包作用域,即便 unused 从来都没有被使用过,它对 originalThing 的引用还是强制它保持活跃状态(阻止它被回收)。当这段代码重复运行时,将可以观察到内存消耗稳定地上涨,并且不会因为 GC 的存在而下降。本质上来讲,创建了一个闭包链表(根节点是 theThing 形式的变量),而且每个闭包作用域都持有一个对大数组的间接引用,这导致了一个巨大的内存泄露。
添加回答
举报
0/150
提交
取消