JavaScript 中的内存泄漏
JavaScript 中的内存泄漏
JavaScript 是一种垃圾收集式语言,这就是说,内存是根据对象的创建分配给该对象的,并会在没有对该对象的引用时由浏览器收回。JavaScript 的垃圾收集机制本身并没有问题,但浏览器在为 DOM 对象分配和恢复内存的方式上却有些出入。
Internet Explorer 和 Mozilla Firefox 均使用引用计数来为 DOM 对象处理内存。在引用计数系统,每个所引用的对象都会保留一个计数,以获悉有多少对象正在引用它。如果计数为零,该对象就会被销毁,其占用的内存也会返回 给堆。虽然这种解决方案总的来说还算有效,但在循环引用方面却存在一些盲点。
循环引用的问题何在?
当两个对象互相引用时,就构成了循环引用,其中每个对象的引用计数值都被赋 1。在纯垃圾收集系统中,循环引用问题不大:若涉及到的两个对象中的一个对象被任何其他对象引用,那么这两个对象都将被垃圾收集。而在引用计数系统,这两 个对象都不能被销毁,原因是引用计数永远不能为零。在同时使用了垃圾收集和引用计数的混合系统中,将会发生泄漏,因为系统不能正确识别循环引用。在这种情 况下,DOM 对象和 JavaScript 对象均不能被销毁。清单 1 显示了在 JavaScript 对象和 DOM 对象间存在的一个循环引用。
清单 1. 循环引用导致了内存泄漏
<html> |
如上述清单中所示,JavaScript 对象 obj
拥有到 DOM 对象的引用,表示为
DivElement
。而 DOM 对象则有到此 JavaScript 对象的引用,由
expandoProperty
表示。可见,JavaScript 对象和 DOM 对象间就产生了一个循环引用。由于 DOM 对象是通过引用计数管理的,所以两个对象将都不能销毁。
另一种内存泄漏模式
在清单 2 中,通过调用外部函数 myFunction
创建循环引用。同样,JavaScript 对象和 DOM 对象间的循环引用也会导致内存泄漏。
清单 2. 由外部函数调用引起的内存泄漏
<html> |
正如这两个代码示例所示,循环引用很容易创建。在 JavaScript 最为方便的编程结构之一:闭包中,循环引用尤其突出。
JavaScript 中的闭包
JavaScript 的过人之处在于它允许函数嵌套。一个嵌套的内部函数可以继承外部函数的参数和变量,并由该外部函数私有。清单 3 显示了内部函数的一个示例。
清单 3. 一个内部函数
function parentFunction(paramA) |
JavaScript 开发人员使用内部函数来在其他函数中集成小型的实用函数。如清单 3 所示,此内部函数 childFunction
可以访问外部函数
parentFunction
的变量。当内部函数获得和使用其外部函数的变量时,就称其为一个闭包 。
了解闭包
考虑如清单 4 所示的代码片段。
清单 4. 一个简单的闭包
<html> |
在上述清单中,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. 由事件处理引起的内存泄漏模式
<html> |
避免内存泄漏
幸好,JavaScript 中的内存泄漏是可以避免的。当确定了可导致循环引用的模式之后,正如我们在上述章节中所做的那样,您就可以开始着手应对这些模式了。这里,我们将以上述的 由事件处理引起的内存泄漏模式为例来展示三种应对已知内存泄漏的方式。
一种应对 清单 5中的内存泄漏的解决方案是让此 JavaScript 对象 obj
为空,这会显式地打破此循环引用,如清单 6 所示。
清单 6. 打破循环引用
<html> |
清单 7 是通过添加另一个闭包来避免 JavaScript 对象和 DOM 对象间的循环引用。
清单 7. 添加另一个闭包
<html> |
清单 8 则通过添加另一个函数来避免闭包本身,进而阻止了泄漏。
清单 8. 避免闭包自身
<html> |
结束语
本文解释了循环引用是如何导致 JavaScript 中的内存泄漏的 —— 尤其是在结合了闭包的情况下。您还了解了涉及到循环引用的一些常见内存泄漏模式以及应对这些泄漏模式的几种简单方式
原文地址:http://wv1124.iteye.com/blog/524896
JavaScript 中的内存泄漏的更多相关文章
- JavaScript中的内存泄漏以及如何处理
随着现在的编程语言功能越来越成熟.复杂,内存管理也容易被大家忽略.本文将会讨论JavaScript中的内存泄漏以及如何处理,方便大家在使用JavaScript编码时,更好的应对内存泄漏带来的问题. 概 ...
- Javascript中的内存泄漏
最新博客站点:欢迎来访 一.内存泄漏 由于某些原因不再需要的内存没有被操作系统或则空闲内存池回收.编程语言中有多种管理内存的方式.这些方式从不同程度上会减少内存泄漏的几率,高级语言嵌入了 ...
- 了解 JavaScript 应用程序中的内存泄漏
简介 当处理 JavaScript 这样的脚本语言时,很容易忘记每个对象.类.字符串.数字和方法都需要分配和保留内存.语言和运行时的垃圾回收器隐藏了内存分配和释放的具体细节. 许多功能无需考虑内存管理 ...
- 高效使用 JavaScript 闭包,避免 Node.js 应用程序中的内存泄漏
在 Node.js 中,广泛采用不同形式的闭包来支持 Node 的异步和事件驱动编程模型.通过很好地理解闭包,您可以确保所开发应用程序的功能正确性.稳定性和可伸缩性. 闭包是一种将数据与处理数据的代码 ...
- javascript中的内存管理和垃圾回收
前面的话 不管什么程序语言,内存生命周期基本是一致的:首先,分配需要的内存:然后,使用分配到的内存:最后,释放其内存.而对于第三个步骤,何时释放内存及释放哪些变量的内存,则需要使用垃圾回收机制.本文将 ...
- JavaScript 中对内存的一些了解
在使用JavaScript进行开发的过程中,了解JavaScript内存机制有助于开发人员能够清晰的认识到自己写的代码在执行的过程中发生过什么,也能够提高项目的代码质量.其实关于内存的文章也有很多,写 ...
- 关于Hash集合以及Java中的内存泄漏
<学习笔记>关于Hash集合以及Java中的内存泄漏 标签: 学习笔记内存泄露hash 2015-10-11 21:26 58人阅读 评论(0) 收藏 举报 分类: 学习笔记(5) 版 ...
- 系统剖析Android中的内存泄漏
[转发]作为Android开发人员,我们或多或少都听说过内存泄漏.那么何为内存泄漏,Android中的内存泄漏又是什么样子的呢,本文将简单概括的进行一些总结. 关于内存泄露的定义,我可以理解成这样 没 ...
- [转载]Java应用程序中的内存泄漏及内存管理
近期发现测试的项目中有JAVA内存泄露的现象.虽然JAVA有垃圾回收的机制,但是如果不及时释放引用就会发生内存泄露现象.在实际工作中我们使用Jprofiler调用java自带的 jmap来做检测还是很 ...
随机推荐
- ios开发——实用技术OC-Swift篇&触摸与手势识别
iOS开发学习之触摸事件和手势识别 iOS的输入事件 触摸事件 手势识别 手机摇晃 一.iOS的输入事件 触摸事件(滑动.点击) 运动事件(摇一摇.手机倾斜.行走),不需要人为参与的 远程控制 ...
- android学习日记27--Dialog使用及其设计模式
1.Dialog概述 对话框一般是一个出现在当前Activity之上的一个小窗口,处于下面的Activity失去焦点, 对话框接受所有的用户交互. 对话框一般用于提示信息和与当前应用程序直接相关的小功 ...
- Ext.Net 问题收集
Ext.Net DateField只显示年月 <ext:DateField runat="server" Format="yyyy-MM"> < ...
- memcached client --ref
Clients Client API's / libraries Updated Jul 14, 2012 by dorma...@rydia.net ref:https://code.google. ...
- web前端开发前景怎么样?
对于web前端开发,对现今前端的发展,中国的发展还很落后,中国没有Jquery,没有Node.js,其中最主要的一点是,中国的前端比较封锁,大家都没有分享的觉悟.回头看看,那些发展比较快的行业.软件, ...
- 想做一个整合开源安全代码扫描工具的代码安全分析平台 - Android方向调研
想做一个整合开源安全代码扫描工具的代码安全分析平台 - Android方向调研 http://blog.csdn.net/testing_is_believing/article/details/22 ...
- 将HTML表格导出到EXCEL,兼容Firefox,支持中文
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- http协议与内容压缩
为了加快网络上的传输的速度,可以将服务器传输的内容进行压缩,服务器的压缩方式有gzip压缩 deflate压缩 compress压缩 content-length:压缩后的长度 如何启动压缩功能 1, ...
- java poi出excel换行问题
POI操作excel实现换行问题. package jp.co.misumi.mdm.batch.common.jobrunner; import java.io.FileInputStream; i ...
- scala学习笔记:集合
scala> 1 to 10 res9: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9 ...