闭包可能导致的内存泄漏

Posted wen_rc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包可能导致的内存泄漏相关的知识,希望对你有一定的参考价值。

什么是闭包

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

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. 函数声明提前

以上是关于闭包可能导致的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

前端知识体系:JavaScript基础-作用域和闭包-闭包的实现原理和作用以及堆栈溢出和内存泄漏原理和相应解决办法

这个 JavaScript 代码会导致内存泄漏吗?

深入了解 JavaScript 内存泄漏

JavaScript内存管理闭包和内存泄漏

深入了解 JavaScript 内存泄漏

闭包会造成内存泄漏吗