导读:
  由于最近自己的FireFox经常出现调用JS脚本时造成内存溢出而产生假死的现象,今天刚好有幸看的IBM网站里这篇文章,而自己现在又在学习JS,看了以后觉得写的非常不错,提到了很多我们平时在编写JS代码时容易造成的错误。现将此文分享给大家!
  Internet Explorer 和 Mozilla Firefox 是两个与 JavaScript 中的内存泄漏联系最为紧密的浏览器。两个浏览器中造成这种问题的“罪魁祸首”是用来管理 DOM 对象的组件对象模型。本机 Windows COM 和 Mozilla's XPCOM 都使用引用计数的垃圾收集来进行内存分配和检索。引用计数与用于 JavaScript 的标记-清除式的垃圾收集并不总是能相互兼容。本文侧重介绍的是如何应对 JavaScript代码中的内存泄漏。JavaScript 中的内存泄漏
  JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回。JavaScript 的垃圾收集机制本身并没有问题,但浏览器在为 DOM 对象分配和恢复内存的方式上却有些出入。
  Internet Explorer 和 Mozilla Firefox 均使用引用计数来为 DOM 对象处理内存。在引用计数系统,每个所引用的对象都会保留一个计数,以获悉有多少对象正在引用它。如果计数为零,该对象就会被销毁,其占用的内存也会返回给堆。虽然这种解决方案总的来说还算有效,但在循环引用方面却存在一些盲点。
  循环引用的问题何在?
  当两个对象互相引用时,就构成了循环引用,其中每个对象的引用计数值都被赋 1。在纯垃圾收集系统中,循环引用问题不大:若涉及到的两个对象中的一个对象被任何其他对象引用,那么这两个对象都将被垃圾收集。而在引用计数系统,这两个对象都不能被销毁,原因是引用计数永远不能为零。在同时使用了垃圾收集和引用计数的混合系统中,将会发生泄漏,因为系统不能正确识别循环引用。在这种情况下,DOM 对象和 JavaScript 对象均不能被销毁。清单 1 显示了在 JavaScript 对象和 DOM 对象间存在的一个循环引用。清单 1. 循环引用导致了内存泄漏
  
  
  
  <script type="text/javascript">
  document.write("circular references between JavaScript and DOM!");
  var obj;
  window.onload = function(){
  obj=document.getElementById("DivElement");
  document.getElementById("DivElement").expandoProperty=obj;
  obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
  };
  </script>
  

Div Element

  
  
  如上述清单中所示,JavaScript 对象 obj 拥有到 DOM 对象的引用,表示为 DivElement。而 DOM 对象则有到此 JavaScript 对象的引用,由 expandoProperty 表示。可见,JavaScript 对象和 DOM 对象间就产生了一个循环引用。由于 DOM 对象是通过引用计数管理的,所以两个对象将都不能销毁。
  另一种内存泄漏模式
  在清单 2 中,通过调用外部函数 myFunction 创建循环引用。同样,JavaScript 对象和 DOM 对象间的循环引用也会导致内存泄漏。
  清单 2. 由外部函数调用引起的内存泄漏
  
  
  
  <script type="text/javascript">
  document.write(" object s between JavaScript and DOM!");
  function myFunction(element)
  {
  this.elementReference = element;
  // This code forms a circular reference here
  //by DOM-->JS-->DOM
  element.expandoProperty = this;
  }
  function Leak() {
  //This code will leak
  new myFunction(document.getElementById("myDiv"));
  }
  </script>
  
  
  
  
  
  正如这两个代码示例所示,循环引用很容易创建。在 JavaScript 最为方便的编程结构之一:闭包中,循环引用尤其突出。
  JavaScript 中的闭包
  JavaScript 的过人之处在于它允许函数嵌套。一个嵌套的内部函数可以继承外部函数的参数和变量,并由该外部函数私有。清单 3 显示了内部函数的一个示例。
  清单 3. 一个内部函数
  
  function parentFunction(paramA)
  {
  var a = paramA;
  function childFunction()
  {
  return a + 2;
  }
  return childFunction();
  }
  JavaScript 开发人员使用内部函数来在其他函数中集成小型的实用函数。如清单 3 所示,此内部函数 childFunction 可以访问外部函数 parentFunction 的变量。当内部函数获得和使用其外部函数的变量时,就称其为一个闭包。
  了解闭包
  考虑如清单 4 所示的代码片段。
  清单 4. 一个简单的闭包
  
  
  
  <script type="text/javascript">
  document.write("Closure Demo!!");
  window.οnlοad=
  function closureDemoParentFunction(paramA)
  {
  var a = paramA;
  return function closureDemoInnerFunction (paramB)
  {
  alert( a +" "+ paramB);
  };
  };
  var x = closureDemoParentFunction("outer x");
  x("inner x");
  </script>
  
  
  在上述清单中,closureDemoInnerFunction 是在父函数 closureDemoParentFunction 中定义的内部函数。当用外部的 x 对 closureDemoParentFunction 进行调用时,外部函数变量 a 就会被赋值为外部的 x。函数会返回指向内部函数 closureDemoInnerFunction 的指针,该指针包括在变量 x 内。
  外部函数 closureDemoParentFunction 的本地变量 a 即使在外部函数返回时仍会存在。这一点不同于 C/C++ 这样的编程语言,在 C/C++ 中,一旦函数返回,本地变量也将不复存在。在 JavaScript 中,在调用 closureDemoParentFunction 的时候,带有属性 a 的范围对象将会被创建。该属性包括值 paramA,又称为“外部 x”。同样地,当 closureDemoParentFunction 返回时,它将会返回内部函数 closureDemoInnerFunction,该函数包括在变量 x 中。
  由于内部函数持有到外部函数的变量的引用,所以这个带属性 a 的范围对象将不会被垃圾收集。当对具有参数值 inner x 的 x 进行调用时,即 x("inner x"),将会弹出警告消息,表明 “outer x innerx”。
  清单 4 简要解释了 JavaScript 闭包。闭包功能非常强大,原因是它们使内部函数在外部函数返回时也仍然可以保留对此外部函数的变量的访问。不幸的是,闭包非常易于隐藏 JavaScript 对象 和 DOM 对象间的循环引用。
  闭包和循环引用
  在清单 5 中,可以看到一个闭包,在此闭包内,JavaScript 对象(obj)包含到 DOM 对象的引用(通过 id "element" 被引用)。而 DOM 元素则拥有到 JavaScript obj 的引用。这样建立起来的 JavaScript 对象和 DOM 对象间的循环引用将会导致内存泄漏。
  清单 5. 由事件处理引起的内存泄漏模式
  
  
  
  <script type="text/javascript">
  document.write("rogram to illustrate memory leak via closure");
  window.οnlοad=function outerFunction(){
  var obj = document.getElementById("element");
  obj.οnclick=function innerFunction(){
  alert("Hi! I will leak");
  };
  obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
  // This is used to make the leak significant
  };
  </script>
   Click Me
  
  
  避免内存泄漏
  幸好,JavaScript 中的内存泄漏是可以避免的。当确定了可导致循环引用的模式之后,正如我们在上述章节中所做的那样,您就可以开始着手应对这些模式了。这里,我们将以上述的 由事件处理引起的内存泄漏模式 为例来展示三种应对已知内存泄漏的方式。
  一种应对 清单 5 中的内存泄漏的解决方案是让此 JavaScript 对象 obj 为空,这会显式地打破此循环引用,如清单 6 所示。
  清单 6. 打破循环引用
  
  
  
  <script type="text/javascript">
  document.write("Avoiding memory leak via closure by breaking the circular
  reference");
  window.οnlοad=function outerFunction(){
  var obj = document.getElementById("element");
  obj.οnclick=function innerFunction()
  {
  alert("Hi! I have avoided the leak");
  // Some logic here
  };
  obj.bigString=new Array(1000).join(new Array(2000).join("XXXXX"));
  obj = null; //This breaks the circular reference
  };
  </script>
   "Click Here"
  
  
  清单 7 是通过添加另一个闭包来避免 JavaScript 对象和 DOM 对象间的循环引用。
  清单 7. 添加另一个闭包
  
  
  
  <script type="text/javascript">
  document.write("Avoiding a memory leak by adding another closure");
  window.οnlοad=function outerFunction(){
  var anotherObj = function innerFunction()
  {
  // Some logic here
  alert("Hi! I have avoided the leak");
  };
  (function anotherInnerFunction(){
  var obj = document.getElementById("element");
  obj.οnclick=anotherObj })();
  };
  </script>
   "Click Here"
  
  
  清单 8 则通过添加另一个函数来避免闭包本身,进而阻止了泄漏。
  清单 8. 避免闭包自身
  
  
  
  <script type="text/javascript">
  document.write("Avoid leaks by avoiding closures!");
  window.οnlοad=function()
  {
  var obj = document.getElementById("element");
  obj.onclick = doesNotLeak;
  }
  function doesNotLeak()
  {
  //Your Logic here
  alert("Hi! I have avoided the leak");
  }
  </script>
  
  
   "Click Here"
  
  
  
  Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1779880

本文转自
http://blog.csdn.net/controlsea/archive/2007/09/10/1779880.aspx

—不积硅步,无以至千里相关推荐

  1. C#操作Excel表格,不积硅步无以至千里

    本文主要介绍一下c#来操作excel表格,主要介绍我使用的,我是使用第三方提供的函数库(NPOI)来进行excel的操作,而NPOI库函数在其官网下,我这里就不拿出来了. 1:NPOI库函数 NPOI ...

  2. 不积硅步 无以至千里

    首先很感谢屏幕前的各位小伙伴观看我的这一篇文章. 自我介绍 我是一位准大一新生,对于计算机有着浓厚的兴趣,但是在高考后我并没有录取到计算机的专业,而是被录取到了离计算机很近的自动化专业,这对于我来说也 ...

  3. SqlServer骚操作,不积硅步无以至千里

    1. 类型转换方法1:Convert(目标类型,待转换的字段,格式) 2. 类型转换方法2:Cast(待转换的字段 as 目标类型) 3. 日期增加:DateAdd(日期的年/月/日...,增加的数值 ...

  4. 不积硅步无以至千里,不积小流无以成江海

    aHR0cHM6Ly93d3cuY25ibG9ncy5jb20vemhhbmdndW9zaGVuZzExMjEvcC8xMTQ0ODE5NC5odG1s 每天进步一点点

  5. ListBox美化重绘,不积硅步无以至千里

    如果要对ListBox控件进行自定义绘制(美化),那么首先必须将ListBox的DrawMode属性设置为OwnerDrawVariable或OwnerDrawFixed.ListBox有个ItemH ...

  6. 常用快捷键,不积硅步无以至千里

    1)全部代码格式整理:Ctrl+K,D  2)所选代码格式整理:Ctrl+K,F  3)智能代码提示:Ctrl+J  4)所选代码注释:Ctrl+K,C  5)所选代码取消注释:Ctrl+K,U  6 ...

  7. 数据库常用命令,不积硅步无以至千里

    1. 查看数据库:Show DataBases; 2. 新建数据库:Create DataBase 库名 characterset 字符集名称 3. 查看数据库信息:Show CreateDataBa ...

  8. HashTable常用方法,不积硅步无以至千里

    1. 创建HashTable对象:HashTable hashTable=new HashTabel(); 2. 添加键值对:hashTable.Add(键,值); 3. 清空键值对:hashTabl ...

  9. string常用方法,不积硅步无以至千里

    1. 字符串至数值转换: 创建转换结果标志:bool successFlag=false; 创建待转换字符串:string age=27; 创建用来保存转换结果值的变量:int result=-1; ...

最新文章

  1. 人脸识别躲不过一张3D面具,安全风险到底有多大?
  2. shell实现矩阵转置
  3. 记一次Socket.IO长链服务的性能压测
  4. NSURL中fileURLWithPath和URLWithString
  5. A - Character Encoding HDU - 6397 - 方程整数解-容斥原理
  6. 如何清空其他终端上的屏幕
  7. 关于bootbox.js自定义弹出框样式,如修改宽度等
  8. Spring中Junit测试启动报错class path resource [xxx.xml] cannot be opened because it does not exist
  9. ireport 循环_IReport 常见问题整理
  10. android shell打包
  11. 【硬件】【RF 连接器】
  12. 什么是操作系统(OS)?都有哪些常见的分类?
  13. Usually, this means that the Expanded widget has the wrong ancestor RenderObjectWidget. Typically, E
  14. js制作点击会自动隐藏的导航栏(固定在在头部的)
  15. 教你怎么阅读外文文献
  16. Tyvj1474 打鼹鼠
  17. Vue和elementUI常用组件问题
  18. 程序员必读的职业规划书,少走 5 年弯路(送书)
  19. linux ioctl 设备只读,linux – lsattr:设备的不适当的ioctl在读取标志时
  20. 调查发现:手机竟然比马桶垫还脏

热门文章

  1. win10电脑日历怎么显示第几周?
  2. 达梦数据库创建及数据库实例管理
  3. springboot vue电影购票选座网站源码
  4. 计算机管理找不到文件怎么办,Windows找不到文件怎么办
  5. Multisim 安装报错:encountered an improper argument 解决方案(部分仪器实用)
  6. 逻辑门电路的延时分析
  7. 【转载】什么是计算机图形学?
  8. 自学软件测试的面试经验(一)~
  9. 用友畅捷通系列软件运行单据列表查询时报“错误‘6’ 溢出”错误!
  10. ios辅助功能_iOS辅助功能标签