题目
今天遇到一道经典的闭包内存泄漏问题,一下还是很难说的很清楚,这里重新理一下闭包的逻辑。
var t = null;
var replaceThing = function() {
var o = t
var unused = function() {
if (o)
console.log("hi")
}
t = {
longStr: new Array(1000000).join('*'),
someMethod: function() {
console.log(1)
}
}
}
setInterval(replaceThing, 1000)
闭包分析
闭包大家都知道,重点从两个方面来理解:
- 函数嵌套函数,内层函数引用了外层函数作用域下的变量,并且内层函数被全局环境下的变量引用,就形成了闭包。
- 函数内部定义的所有函数共享同一个闭包对象。
所以,看到一个函数先确定其中的函数嵌套关系,再看是否内层函数引用了外层函数作用域下的变量,这道题目中,内层函数unused
引用了外层函数replaceThing
作用域中的变量o
, 这里就有了一个闭包对象,假如没有后面的t
对象,由于函数unused
并没有被全局变量引用,这个闭包对象在函数执行完后就销毁了。
但是我们看后面的代码,someMethod
函数组成一个大对象被赋值给了全局变量t
,这里就符合了定义“内层函数被全局环境下的变量引用”,但是很多人有疑问我这个方法里没有引用外层函数的变量啊,这里就正好符合了第二条定义“函数内部定义的所有函数共享同一个闭包对象”,因此someMethod
函数跟unused
共享了同一个闭包对象,隐式持有了变量o
的引用,形成了一个 t -> someMethod -> o ->上一次t -> ...
的循环引用, 造成了内存泄漏。
解决方法
切断这个循环引用也就是说切断o
到上一次t
的引用,即在函数知性最后加上o = null
即可。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。