龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > Javascript编程 >

深入浅出JavaScript内存泄漏(1)(2)

时间:2013-03-06 14:58来源:未知 作者:admin 点击:
分享到:
Figure 1: 基本的循环引用模型 本模型中引起的泄漏问题基于COM的引用计数。脚本引擎对象会维持对DOM对象的引用,并在清理和释放DOM对象指针前等待所有引

Figure 1: 基本的循环引用模型

本模型中引起的泄漏问题基于COM的引用计数。脚本引擎对象会维持对DOM对象的引用,并在清理和释放DOM对象指针前等待所有引用的移除。在我们的示例 中,我们的脚本引擎对象上有两个引用:脚本引擎作用域和DOM对象的expando属性。

当终止脚本引擎时第一个引用会释放,DOM对象引用由于在等待脚 本擎的释放而并不会被释放。你可能会认为检测并修复假设的这类问题会非常的容易,但事实上这样基本的的示例只是冰山一角。你可能会在30个对象链的末尾发 生循环引用,这样的问题排查起来将会是一场噩梦。如果你仍不清楚这种泄漏方式在HTML代码里到底怎样,你可以通过一个全局脚本变量和一个DOM对象来引发并展现它。

  1. <html> 
  2. <head> 
  3. <script language="JavaScript"> 
  4. var myGlobalObject;  
  5. function SetupLeak()  
  6. {  
  7. // First set up the script scope to element reference  
  8. myGlobalObject = document.getElementById("LeakedDiv");  
  9.  
  10. // Next set up the element to script scope reference  
  11. document.getElementById("LeakedDiv").expandoProperty = myGlobalObject;  
  12. }  
  13.  
  14. function BreakLeak()  
  15. {  
  16. document.getElementById("LeakedDiv").expandoProperty = null;  
  17. }  
  18. </script> 
  19. </head> 
  20. <body onload="SetupLeak()" onunload="BreakLeak()"> 
  21. <div id="LeakedDiv"></div> 
  22. </body> 
  23. </html> 

你可以使用直接赋null值得方式来破坏该泄漏情形。在页面文档卸载前赋null值,将会让脚本引擎知道对象间的引用链没有了。现在它将能正常的清理引用 并释放DOM对象。在这个示例中,作为Web开发员的你因该更多的了解了对象间的关系。

作为一个基本的情形,循环引用可能还有更多不同的复杂表现。对基于对象的JavaScript,一个通常用法是通过封装JavaScript对象来扩充DOM对象。在 构建过程中,你常常会把DOM对象的引用放入JavaScript对象中,同时在DOM对象中也存放上对新近创建的JavaScript对象的引用。你的这种应用模式 将非常便于两个对象之间的相互访问。这是一个非常直接的循环引用问题,但是由于使用不用的语法形式可能并不会让你在意。要破环这种使用情景可能变得更加复 杂,当然你同样可以使用简单的示例以便于清楚的讨论。

  1. <html> 
  2. <head> 
  3. <script language="JavaScript"> 
  4.  
  5. function Encapsulator(element)  
  6. {  
  7. // Set up our element  
  8. this.elementReference = element;  
  9.  
  10. // Make our circular reference  
  11. element.expandoProperty = this;  
  12. }  
  13.  
  14. function SetupLeak()  
  15. {  
  16. // The leak happens all at once  
  17. new Encapsulator(document.getElementById("LeakedDiv"));  
  18. }  
  19.  
  20. function BreakLeak()  
  21. {  
  22. document.getElementById("LeakedDiv").expandoProperty = null;  
  23. }  
  24. </script> 
  25. </head> 
  26. <body onload="SetupLeak()" onunload="BreakLeak()"> 
  27. <div id="LeakedDiv"></div> 
  28. </body> 
  29. </html> 

更复杂的办法还有记录所有需要解除引用的对象和属性,然后在Web文档卸载的时候统一清理,但大多数时候你可能会再造成额外的泄漏情形,而并没有解决你的 问题。

闭包函数(Closures)

由于闭包函数会使程序员在不知不觉中创建出循环引用,所以它对资源泄漏常常有着不可推卸的责任。而在闭包函数自己被释放前,我们很难判断父函数的参数以及 它的局部变量是否能被释放。实际上闭包函数的使用已经很普通,以致人们频繁的遇到这类问题时我们却束手无策。在详细了解了闭包背后的问题和一些特殊的闭包 泄漏示例后,我们将结合循环引用的图示找到闭包的所在,并找出这些不受欢迎的引用来至何处。

精彩图集

赞助商链接