魔鬼的梦魇—验证IE中的JS内存泄露(二)

闭包往往是需要为内存泄露负责的,因为使用它会很容易产生不为程序员所发现的循环引用。父函数的参数和局部变量将会一直被冻结、引用和持有,知道闭包本身被释放,这并不是显而易见的。事实上闭包已经变成如此普遍的变成策略,以至于开发人员经常的深陷问题之中,但是已存的我们可以依赖使用的资源却很少。我们来看看这个使用了闭包的循环引用图,它详细的描述了闭包及其造成的没存泄露的由来,并且指出了这些循环引用是如何形成的。

一般情况下的循环引用时由于两个特定的对象彼此持有对方的引用造成的,但是闭包却不一样。它不是直接引用,而是其通过引入父函数的作用域信息而产生的。正常情况下,一个函数的局部变量和参数仅仅在函数被调用的生命周期内才能被使用。但是只要闭包存在的话,这些变量和参数就一直被引用,并且由于闭包的生命周期可能会超过父函数,所以这些局部变量和参数同样也会。在这个原理图(图1)中,只要父函数一执行完,就会释放对参数parameter1的引用。但是由于我们添加了一个闭包,这个闭包又添加了自己对parameter1的引用,但是这个引用直到这个闭包被释放的时候才会被释放。如果以正好将这个闭包绑定到一个事件,那么最终你就需要解除对这个事件的绑定。如果你将这个闭包绑定到DOM的属性expando,那么你最终页需要将这个属性重置为null。

魔鬼的梦魇—验证IE中的JS内存泄露(二)

图 1. 闭包导致内存泄露原理图

每调用一次函数就会产生一个新的闭包对象,所以调用两次父函数那么就是产生两个相互独立的闭包对象,每一个闭包都会引用产生自己的时候传入的参数。这种显而易见的特性是很容易导致内存泄露的。原理图对应的对象引用关系图如下(图2)

魔鬼的梦魇—验证IE中的JS内存泄露(二)

图 2. 闭包泄露原理图对象引用关系图

在这个模式中给出的例子也是使用的页面中的DOM元素,我们也是测试不到内存泄露的,因为本质上说这个也是由于循环引用导致。修改的可以导致泄露的代码如下,具体的验证图片就不贴出来了,有兴趣的话可以自己测试一下

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script language="JScript"> function AttachEvents(element) { // This structure causes element to ref ClickEventHandler element.attachEvent("onclick", ClickEventHandler); function ClickEventHandler() { // This closure refs element } } function SetupLeak() { // The leak happens all at once AttachEvents(document.createElement("<div/>")); } function BreakLeak() { } </script> </head\> <body onload="SetupLeak()" onunload="BreakLeak()"> <div id="LeakedDiv"></div> </body> </html>

相关文章:

  • 2022-01-12
  • 2021-05-12
  • 2022-12-23
  • 2022-01-03
  • 2021-08-27
  • 2021-07-17
  • 2021-12-07
  • 2021-11-10
猜你喜欢
  • 2021-12-11
  • 2021-05-31
  • 2021-12-29
  • 2021-09-18
相关资源
相似解决方案