什么是JavaScript垃圾收集?为了编写更好的代码,Web程序员理解JavaScript垃圾收集有什么重要意义?
Eric Lippert不久前写了一篇关于这个主题的详细博客文章(另外将它与VBScript进行比较).更准确地说,他撰写了关于JScript的文章,这是微软自己的ECMAScript实现,虽然与JavaScript非常相似.我想你可以假设绝大多数行为对于Internet Explorer的JavaScript引擎都是一样的.当然,实现方式因浏览器而异,但我怀疑您可以采用一些通用原则并将其应用于其他浏览器.
引自该页面:
JScript使用非代数标记和清除垃圾收集器.它的工作原理如下:
"范围内"的每个变量都称为"清道夫".清道夫可以指数字,对象,字符串等等.我们维护一个清道夫列表 - 当变量进入范围时变量被移动到scav列表,当它们超出范围时变量离开scav列表.
垃圾收集器时不时地运行.首先,它在每个对象,变量,字符串等上放置一个"标记" - GC跟踪的所有内存.(JScript在内部使用VARIANT数据结构,在该结构中有大量额外的未使用位,因此我们只设置其中一个.)
其次,它清除了清道夫的标记和清道夫参考的传递关闭.因此,如果一个清道夫对象引用了一个非移民对象,那么我们清除非移民对象以及它引用的所有内容.(我使用"封闭"一词的意义与我之前的帖子不同.)
此时我们知道仍然标记的所有内存都是已分配的内存,任何范围内变量的任何路径都无法访问该内存.所有这些物体都被指示将它们撕下来,这会破坏任何循环引用.
垃圾收集的主要目的是让程序员不要担心他们创建和使用的对象的内存管理,虽然当然有时候无法避免它 - 至少对垃圾收集的工作方式有一个大致的了解总是有益的. .
有几点需要注意.Apple开发者网站对此事有一些指导.那里有两个重要的:
使用删除语句.每当使用新语句创建对象时,请将其与delete语句配对.这可确保与对象关联的所有内存(包括其属性名称)都可用于垃圾回收.删除语句将在"释放对象"中进行更多讨论.
使用var关键字.在没有var关键字的情况下创建的任何变量都是在全局范围内创建的,并且永远不会有资格进行垃圾回收,从而导致内存泄漏.
我认为这些实践应该适用于所有JavaScript引擎(在不同的浏览器中),但因为这是来自Apple网站,它们可能在某种程度上与Safari有关.(也许有人可以澄清一下?)
希望有所帮助.
涉及DOM对象时要小心循环引用:
JavaScript中的内存泄漏模式
请记住,只有在没有对象的活动引用时才能回收内存.这是闭包和事件处理程序的常见缺陷,因为一些JS引擎不会检查内部函数中实际引用的变量,只保留封闭函数的所有局部变量.
这是一个简单的例子:
function init() { var bigString = new Array(1000).join('xxx'); var foo = document.getElementById('foo'); foo.onclick = function() { // this might create a closure over `bigString`, // even if `bigString` isn't referenced anywhere! }; }
bigString
只要事件处理程序存在,就无法收集天真的JS实现.有几种方法可以解决这个问题,例如设置bigString = null
在末尾init()
(delete
不适用于局部变量和函数参数:delete
从对象中删除属性,并且变量对象不可访问 - 严格模式下的ES5甚至会抛出一个,ReferenceError
如果你尝试删除局部变量!).
如果您关心内存消耗,我建议尽可能避免不必要的关闭.
引自博客的好报价
DOM组件是"垃圾收集",JScript组件也是如此,这意味着如果您在任一组件中创建一个对象,然后失去对该对象的跟踪,它最终将被清除.
例如:
function makeABigObject() { var bigArray = new Array(20000); }
当您调用该函数时,JScript组件会创建一个可在函数中访问的对象(名为bigArray).但是,一旦函数返回,你就会"失去对bigArray的追踪",因为再也无法引用它了.好吧,JScript组件意识到你已经忘记了它,所以bigArray被清理 - 它的内存被回收.同样的事情在DOM组件中起作用.如果你说document.createElement('div')
或类似的东西,那么DOM组件会为你创建一个对象.一旦你以某种方式失去对该对象的跟踪,DOM组件将清理相关的.
据我所知,当对象没有引用时,JavaScript的对象会定期进行垃圾回收.这是自动发生的事情,但是如果你想了解更多关于它是如何工作的,那么在C++级别,看看WebKit或V8源代码是有意义的.
通常,您不需要考虑它,但是,在旧版浏览器中,如IE 5.5和早期版本的IE 6,以及当前版本,闭包会创建循环引用,当取消选中时最终会占用内存.在我关于闭包的特定情况下,就是当你向dom对象添加JavaScript引用时,以及向DOM对象添加引用回JavaScript对象的对象.基本上它永远不会被收集,并最终导致操作系统在循环创建崩溃的测试应用程序中变得不稳定.在实践中,这些泄漏通常很小,但为了保持代码清洁,您应该删除对DOM对象的JavaScript引用.
通常最好使用delete关键字立即取消引用您收到的JSON数据等大对象,并完成您需要做的任何事情,尤其是在移动Web开发中.这会导致GC的下一次扫描删除该对象并释放其内存.
垃圾收集(GC)是一种自动内存管理形式,它通过删除不再需要的对象.
任何进程处理内存遵循以下步骤:
1 - 分配您需要的内存空间
2 - 做一些处理
3 - 释放这个记忆空间
有两种主要算法用于检测不再需要哪些对象.
引用计数垃圾收集:此算法将"不再需要对象"的定义减少为"对象没有其他对象引用它",如果没有引用指向该对象,则该对象将被删除
标记和扫描算法:将每个对象连接到根源.任何对象都不会连接到root或其他对象.此对象将被删除.
目前大多数现代浏览器使用第二种算法.