- 浏览: 1595976 次
- 性别:
文章分类
- 全部博客 (2929)
- 非技术 (18)
- Eclipse (11)
- JAVA (31)
- 正则表达式 (0)
- J2EE (4)
- DOS命令 (2)
- WEB前端 (52)
- JavaScript (69)
- 数据库 (8)
- 设计模式 (0)
- JFreechart (1)
- 操作系统 (1)
- 互联网 (10)
- EasyMock (1)
- jQuery (5)
- Struts2 (12)
- Spring (24)
- 浏览器 (16)
- OGNL (1)
- WebService (12)
- OSGi (14)
- 软件 (10)
- Tomcat (2)
- Ext (3)
- SiteMesh (2)
- 开源软件 (2)
- Hibernate (2)
- Quartz (6)
- iBatis (2)
最新评论
JavaScript 中的内存泄露模式
JavaScript 是用来向 Web 页面添加动态内容的一种功能强大的脚本语言。它尤其特别有助于一些日常任务,比如验证密码和创建动态菜单组件。JavaScript 易学易用,但却很容易在某些浏览器中引起内存的泄漏。在这个介绍性的文章中,我们解释了 JavaScript 中的泄漏由何引起,展示了常见的内存泄漏模式,并介绍了如何应对它们。
注 意本文假设您已经非常熟悉使用 JavaScript 和 DOM 元素来开发 Web 应用程序。本文尤其适合使用 JavaScript 进行 Web 应用程序开发的开发人员,也可供有兴趣创建 Web 应用程序的客户提供浏览器支持以及负责浏览器故障排除的人员参考。
|
JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回。JavaScript 的垃圾收集机制本身并没有问题,但浏览器在为 DOM 对象分配和恢复内存的方式上却有些出入。
Internet Explorer 和 Mozilla Firefox 均使用引用计数来为 DOM 对象处理内存。在引用计数系统,每个所引用的对象都会保留一个计数,以获悉有多少对象正在引用它。如果计数为零,该对象就会被销毁,其占用的内存也会返回 给堆。虽然这种解决方案总的来说还算有效,但在循环引用方面却存在一些盲点。
当 两个对象互相引用时,就构成了循环引用,其中每个对象的引用计数值都被赋 1。在纯垃圾收集系统中,循环引用问题不大:若涉及到的两个对象中的一个对象被任何其他对象引用,那么这两个对象都将被垃圾收集。而在引用计数系统,这两 个对象都不能被销毁,原因是引用计数永远不能为零。在同时使用了垃圾收集和引用计数的混合系统中,将会发生泄漏,因为系统不能正确识别循环引用。在这种情 况下,DOM 对象和 JavaScript 对象均不能被销毁。清单 1 显示了在 JavaScript 对象和 DOM 对象间存在的一个循环引用。
|
如上述清单中所示,JavaScript 对象 obj
拥有到 DOM 对象的引用,表示为
DivElement
。而 DOM 对象则有到此 JavaScript 对象的引用,由 expandoProperty
表示。可见,JavaScript 对象和 DOM 对象间就产生了一个循环引用。由于 DOM 对象是通过引用计数管理的,所以两个对象将都不能销毁。
在清单 2 中,通过调用外部函数 myFunction
创建循环引用。同样,JavaScript 对象和 DOM 对象间的循环引用也会导致内存泄漏。
|
正如这两个代码示例所示,循环引用很容易创建。在 JavaScript 最为方便的编程结构之一:闭包中,循环引用尤其突出。
|
|
JavaScript 的过人之处在于它允许函数嵌套。一个嵌套的内部函数可以继承外部函数的参数和变量,并由该外部函数私有。清单 3 显示了内部函数的一个示例。
|
JavaScript 开发人员使用内部函数来在其他函数中集成小型的实用函数。如清单 3 所示,此内部函数 childFunction
可以访问外部函数 parentFunction
的变量。当内部函数获得和使用其外部函数的变量时,就称其为一个闭包
。
考虑如清单 4 所示的代码片段。
|
在上述清单中,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 对象间的循环引用将会导致内存泄漏。
|
|
|
幸好,JavaScript 中的内存泄漏是可以避免的。当确定了可导致循环引用的模式之后,正如我们在上述章节中所做的那样,您就可以开始着手应对这些模式了。这里,我们将以上述的 由事件处理引起的内存泄漏模式 为例来展示三种应对已知内存泄漏的方式。
一种应对 清单
5
中的内存泄漏的解决方案是让此 JavaScript 对象 obj
为空,这会显式地打破此循环引用,如清单 6 所示。
|
清单 7 是通过添加另一个闭包来避免 JavaScript 对象和 DOM 对象间的循环引用。
|
清单 8 则通过添加另一个函数来避免闭包本身,进而阻止了泄漏。
|
|
|
本文解释了循环引用是如何导致 JavaScript 中的内存泄漏的 —— 尤其是在结合了闭包的情况下。您还了解了涉及到循环引用的一些常见内存泄漏模式以及应对这些泄漏模式的几种简单方式。有关本文所讨论的主题的更多信息,请参看 参考资料 。
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文
。
- “JavaScript and the Document Object Model
”(Nicholas Chase,developerWorks,2002 年 7 月):为 JavaScript 开发人员介绍了 DOM。
- “跨越边界:闭包
”(Bruce Tate,developerWorks,2007 年 1 月):有关闭包的入门文章(基于 Ruby,但理论上也可以应用到 JavaScript)。
- “JavaScript 中的有限状态机,第 1 部分: 设计一个小部件
”(Edward J. Pring,developerWorks,2007 年 1 月):使用闭包和 JavaScript 的其他高级特性的有趣练习。
- “A re-introduction to javascript
”(Simon Wilson,Mozilla.org):有关 JavaScript 及其特性的深入介绍。
- “Using XPCOM in JavaScript without leaking
”(David Baron,Mozilla.org):解释了 Firefox 为何使用引用计数来进行内存分配以及它又是如何进行这种分配的。
- “对 HTML 页上 DOM 对象循环引用导致内存泄漏
”(Microsoft 帮助和支持):了解 Microsoft 对 IE 中的内存泄漏作何解释。
- “Memory leakage in Internet Explorer -- revisited
”(Volkan Ozcelik,The Code Project,2005 年 11 月):有关 JavaScript 中常见的内存泄漏原因(针对 IE)的教程式介绍。
- “developerWorks Web 开发专区
:内含大量有关 Web 2.0、Ajax、wikis、PHP、mashups 和其他 Web 项目的资源。
获得产品和技术
- IBM 产品的评估版 :实际体验来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。
讨论
Abhijeet Bhattacharya 是 IBM 印度软件实验室的一名系统工程师。在过去三年中,他一直是 OS/2 IBM Web Browser 支持团队中的一员。他也具有系统管理领域的相关经验,并参与过 IBM Pegasus 开源创新项目。他目前工作的重点包括分布式计算和 SARPC。他拥有 Rajiv Gandhi Technical University 的工程学士学位。 |
Kiran Shivarama Sundar 是 IBM 印度软件实验室的一名系统工程师。在过去三年中,他一直是 OS/2 IBM Web Browser 支持团队中的一员。他同时也具有诸多其他项目的工作经验,包括为 Apache Tuscany Open Source Project 开发命令行工具以及为 IBM 的 EPCIS 团队开发 RFIDIC Installer。目前,Kiran 加入了 IBM WebSphere Adapters 支持团队,负责提供对 JMS 和 MQ 适配器的支持。他已成功获得了 Sun Certified Java Programmer、Sun Certified Web Component Developer 和 Sun Certified Business Component Developer 的认证。他目前所关注的领域包括 Java、J2EE、Web 服务和 SOA。他拥有 Visweshwaraya Technology University 的工程学士学位。 |
相关推荐
如果您知道内存泄漏的起因,那么在 JavaScript 中进行相应的防范就应该相当容易。在这篇文章中,作者 Kiran Sundar 和 Abhijeet Bhattacharya 将带您亲历 JavaScript 中的循环引用的全部基本知识,向您介绍为何它们...
如果您知道内存泄漏的起因,那么在 JavaScript 中进行相应的防范就应该相当容易。在这篇文章中,作者 Kiran Sundar 和 Abhijeet Bhattacharya 将带您亲历 JavaScript 中的循环引用的全部基本知识,向您介绍为何它们...
JavaScript 中的内存泄露模式_filesJavaScript高级应用(一) - 静 - CSDNBlog_files javascript函数作用域与闭包 - dh20156's New World!_filesjavascript如何避免内存泄露 - - JavaEye技术网站_filesprototype_js...
本文实例讲述了JavaScript设计模式之单例模式。分享给大家供大家参考,具体如下: 一、单例模式概念 单例就是保证一个类只有一...2、闭包容易造成内存泄露,不需要的要赶快干掉 3、注意new的成本。(继承) 三、单例模
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
116、JavaScript中的对象. 25 117、function的用法 26 118、对象的继承 27 119、this的用法 29 120、Array in JavaScript 29 121、jsp有哪些内置对象?作用分别是什么? 31 122、jsp有哪些动作?作用分别是什么? 31 123...
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
多进程:多进程的设计给你带来不崩溃、不死锁、没有内存泄露的网络浏览器体验和高稳定性。当一个标签死锁的时候,他不会导致你整个浏览器没响应或者其他页面死锁。 在线书签:通过Avant的在线存储可以任何地方,办...
31、java 中会存在内存泄漏吗,请简单描述。 11 32、abstract 的method 是否可同时是static,是否可同时是native,是否可同时是synchronized? 11 33、静态变量和实例变量的区别? 11 34、是否可以从一个static 方法...
在访问量比较大的情况下,可以不用担心发生内存泄露的情况. 配置一个creator的创建和远程方法调用设置: <create creator="new" javascript="Blah"> ... 上面的配置信息表示将java.util.date提供给客户端调用...
内存泄露; 二、CPU的使用率不断上升,内存的使用率也是不断上升,其他一切都很正常; 表明系统中可能产生资源争用情况; 引起原因: 开发人员注意资源调配问题。 三、 所有的事务响应时间、cpu等都很...
7.4.2 推理:找出代码中的“解密-执行”模式 172 7.4.3 检证:确定“解密-执行”模式的位置和方法 175 7.4.4 追踪:使用浏览器特性判断用户环境 179 7.4.5 利用漏洞CVE-2014-6332发起攻击 188 7.5 本章小结 190...