闭包可能导致的内存泄漏

什么是闭包

闭包是函数可以保留和访问其外部变量,比如

let a = 1
let b = function() {
    
    
	console.log(a)
}

这里变量b指向的函数可以访问外面的变量,你会说这不是废话吗?函数都可以访问外部变量呀
那再看一个例子

function f() {
    
    
  let value = 123;

  return function() {
    
    
    alert(value);
  }
}

let g = f(); 

这里函数f执行后,value值是不会被回收的,因为变量g有对函数f的返回有个引用,这个返回是个函数,函数里用到了value,这里也是个闭包。
通过闭包可以保留外部变量的特性,可以实现一些功能,比如

function add() {
    
    
	let value = 0
	return function(v) {
    
    
		value += v
		return value
	}
}
let a = add()
console.log(a(1)) // 1
console.log(a(2)) // 3

闭包造成的内存泄漏

先看看这段代码

let theThing = null;
let replaceThing = function () {
    
    
  let leak = theThing;
  let unused = function () {
    
    
    if (leak)
      console.log("hi")
  };

  theThing = {
    
    
    longStr: new Array(1000000),
    someMethod: function () {
    
    
      console.log('a');
    }
  };
};

这里如果replaceThing执行了多次,就会造成内存泄漏。一开始我也没搞懂,这里不就最多同时存在两份大内存吗?就是当次的theThing变量和leak变量指向上次的theThing变量,没有形成一条引用链呀?

你要说someMethod方法里,如果用到了leak,那someMethod有对leak的引用,然后当下次replaceThing执行时,新的leak指向了上次的theThing,上次的theThing的someMethod里又引用了旧的leak,这样就形成了leak->someMethod->leak->someMethod… 的引用链。

通过chrome的devtools的内存分析工具也能看到这个引用链

但someMethod里没有对leak的引用呀?
这里就是闭包形成的内存泄漏,someMethod指向的函数能访问外部变量,这里就包括了leak,哪怕他内部没有用到leak,但他所处的环境却用到了。
在这里插入图片描述
你会说unused都没用到,不是会被引擎优化掉吗?甚至都没这个变量了。
是的unused被优化掉了。
在这里插入图片描述

但函数的定义还是有的,函数里用到leak,所以leak变量没被优化。那这个函数连名字都没用呀,都调用不了,怎么不顺便优化了?

在这里插入图片描述
这里是没理解的,不过这种情况实际上更早就能发现
在这里插入图片描述
ts就报错了。

但浏览器认为leak有用到就说明这个匿名还是还是被定义了,难道是漏优化了?可能之后这个case就不会内存泄漏了。有大佬知道咋回事吗?

参考资料

  1. 变量作用域,闭包
  2. 函数声明提前

猜你喜欢

转载自blog.csdn.net/ZhaoBuDaoFangXia/article/details/129039616