什么是JavaScript垃圾回收?对于Web程序员来说,了解JavaScript垃圾收集对于编写更好的代码有什么重要意义?
答案 0 :(得分:187)
Eric Lippert不久前写了一篇关于这个主题的detailed blog post(另外将它与 VBScript 进行比较)。更准确地说,他写了JScript,这是微软自己的ECMAScript实现,虽然与JavaScript非常相似。我想你可以假设绝大多数行为对于Internet Explorer的JavaScript引擎都是一样的。当然,实现方式因浏览器而异,但我怀疑您可以采用一些通用原则并将其应用于其他浏览器。
从该页面引用:
JScript使用非代数 标记和清除垃圾收集器。它 是这样的:
“范围内”的每个变量 被称为“清道夫”。一个清道夫 可以指数字,对象,a 串,无论如何。我们保留一份清单 清道夫 - 变量被移动 来到scav列表时他们来了 进入范围并离开scav列表时 它们超出了范围。
时不时的垃圾 收集器运行。首先它放一个 每个对象上的“标记”,变量, 字符串等 - 跟踪的所有内存 由GC。 (JScript使用VARIANT 内部和那里的数据结构 有很多额外的未使用位 那个结构,所以我们只设置一个 它们。)
其次,它清除了标记 清道夫和传递封闭 清道夫参考文献。所以,如果一个 清道夫对象引用a nonscavenger对象,然后我们清除 nonscavenger上的位,然后打开 它涉及的一切。 (我是 在a中使用“闭包”一词 与我之前的感觉不同 交)。
此时我们知道所有的 仍标记的内存已分配 任何人都无法达到的记忆 来自任何范围内变量的路径。所有 指示这些对象 撕裂自己,摧毁 任何循环引用。
垃圾收集的主要目的是让程序员不担心他们创建和使用的对象的内存管理,虽然当然有时候无法避免它 - 总是有益的至少粗略地了解垃圾收集的工作原理。
有几点需要注意。关于此事,Apple开发者网站有some guidelines。两个重要的那个:
我认为这些做法应该适用于所有JavaScript引擎(在不同的浏览器中),但因为这是来自Apple网站,所以可能在某种程度上特定于Safari。 (也许有人可以澄清一下?)
希望有所帮助。
答案 1 :(得分:52)
在涉及DOM对象时要小心循环引用:
Memory leak patterns in 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!
};
}
只要事件处理程序存在,天真的JS实现就无法收集bigString
。有几种方法可以解决这个问题,例如在bigString = null
结束时设置init()
(delete
对局部变量和函数参数不起作用:delete
从中移除属性对象,并且变量对象不可访问 - 如果您尝试删除局部变量,ES5在严格模式下甚至会抛出ReferenceError
。
如果您关心内存消耗,我建议尽可能避免不必要的关闭。
答案 2 :(得分:15)
来自博客的好报价
DOM组件是“垃圾收集”,JScript组件也是如此,这意味着如果您在任一组件中创建对象,然后失去对该对象的跟踪,它最终将被清除。
例如:
function makeABigObject() {
var bigArray = new Array(20000);
}
当您调用该函数时,JScript组件会创建一个可在函数中访问的对象(名为bigArray)。但是,一旦函数返回,你就会“失去对bigArray的追踪”,因为再也无法引用它了。好吧,JScript组件意识到你已经忘记了它,所以bigArray被清理 - 它的内存被回收。同样的事情在DOM组件中起作用。如果你说document.createElement('div')
或类似的东西,那么DOM组件会为你创建一个对象。一旦你以某种方式失去对该对象的跟踪,DOM组件将清理相关的。
答案 3 :(得分:13)
据我所知,当对象没有引用时,JavaScript的对象会定期进行垃圾回收。这是自动发生的事情,但是如果你想了解它的工作原理,那么在C ++级别,看看WebKit或V8 source code
是有意义的。通常你不需要考虑它,但是,在旧的浏览器中,比如IE 5.5和早期版本的IE 6,也许是当前版本,闭包会创建循环引用,当取消选中时最终会占用内存。在我所说的闭包的特定情况下,就是当你向dom对象添加一个JavaScript引用,以及一个引用回JavaScript对象的DOM对象的对象。基本上它永远不会被收集,并最终导致操作系统在循环创建崩溃的测试应用程序中变得不稳定。实际上,这些泄漏通常很小,但为了保持代码清洁,您应该删除对DOM对象的JavaScript引用。
通常最好使用delete关键字立即取消引用您收到的JSON数据等大对象,并完成您需要处理的任何内容,尤其是在移动Web开发中。这会导致GC的下一次扫描移除该对象并释放其内存。
答案 4 :(得分:6)
垃圾收集(GC)是一种通过删除不再需要的对象来自动进行内存管理的一种形式。
处理内存的任何进程都遵循以下步骤:
1 - 分配您需要的内存空间
2 - 做一些处理
3 - 释放这个记忆空间
有两种主要算法用于检测不再需要的对象。
引用计数垃圾收集:此算法减少了&#34的定义;不再需要对象" to"一个对象没有引用它的其他对象"如果没有引用它就会删除该对象
标记和扫描算法:将每个对象连接到根源。任何对象都不能连接到root或其他对象。该对象将被删除。
目前大多数现代浏览器使用第二种算法。
答案 5 :(得分:4)
“在计算机科学中,垃圾收集(GC)是一种自动内存管理的形式。垃圾收集器,或者只是收集器,试图回收垃圾,或者由应用程序永远不会再访问或变异的对象使用的内存。“
所有JavaScript引擎都有自己的垃圾收集器,它们可能不同。大多数时候你不必处理它们,因为它们只是做他们应该做的事情。
编写更好的代码主要取决于您对编程原则,语言和特定实现的了解程度。
答案 6 :(得分:1)
什么是JavaScript垃圾回收?
检查this
对于Web程序员来说理解JavaScript垃圾收集的重要性, 为了写出更好的代码?
在Javascript中,您不关心内存分配和释放。 Javascript解释器需要整个问题。在Javascript中仍然存在泄漏,但它们是解释器的错误。如果您对此主题感兴趣,可以阅读更多内容 www.memorymanagement.org
答案 7 :(得分:1)
在Windows上,您可以使用Drip.exe查找内存泄漏或检查您的免费mem例程是否有效。
这很简单,只需输入一个网站URL,您就会看到集成IE渲染器的内存消耗。然后点击刷新,如果内存增加,你在网页的某个地方发现了内存泄漏。但这对于查看释放内存的例程是否适用于IE也非常有用。
答案 8 :(得分:0)
引用类型不会将对象直接存储到变量中 分配给它的对象,因此本例中的对象变量实际上并没有 包含对象实例。相反,它持有指向的指针(或引用) 对象在内存中的位置
var object = new Object();
如果您将一个变量分配给另一个,则每个变量 获取指针的副本,并且两者仍引用相同的对象 记忆。
var object1 = new Object();
var object2 = object1;
JavaScript是一种垃圾收集语言,因此您实际上不需要 使用引用类型时,请担心内存分配。然而, 最好取消引用不再需要的对象,以免造成垃圾 收集器可以释放该内存。最好的方法是设置 对象变量为null。
var object1 = new Object();
// do something
object1 = null; // dereference
取消引用对象在使用数百万个对象的大型应用程序中尤其重要。
来自面向对象JavaScript的原理-NICHOLAS C. ZAKAS
答案 9 :(得分:0)
在 javascript 中,垃圾收集是不确定的,对象何时会被清除,或者是否会被清除。这适用于强引用的对象。强引用对象不受垃圾收集的影响。
在 ES12 之后,可以通过以下实现来检查对象何时被垃圾回收。
要了解有关 JavaScript 中垃圾收集的更多信息,您可以使用 ES12 之后可用的 Finalisers。
let a = new Array(200).fill(true);
构造终结器
const cleanup = new FinalizationRegistry(key => {
// your code here
});
cleanup.register(a, 'wewew');
对象 'a' 现在不可访问,垃圾回收后将发生终结器回调