Javascript 内存重新分配
Javascript Memory Deallocation
我有一个关于垃圾收集在 Javascript 中如何工作的快速问题。
如果我有这个代码:
var c = {name : ‘Bob’};
c = {name : ‘Mary’};
在上面的代码中,变量 c 指向对象 {name : 'Bob'}。但后来我将 c 设置为指向内存中的另一个对象 {name : 'Mary'}。 c 最初指向的对象 ({name : 'Bob'}) 会怎样?由于不再有对它的引用,是否会在内存中释放该原始对象?
另一种情况:
var c = {name : ‘Bob’};
d = c;
c = {name : ‘Mary’};
现在,c 指向的原始对象 ({name : 'Bob'}) 不会被释放,因为即使 "c" 更改后 d 仍指向 {name : 'Bob'}指向新对象:{name : 'Mary'}。正确吗?
所以基本上一个对象不会从内存中释放,只要有引用仍然指向它。
如果我的想法正确,有人可以向我解释一下吗?
正确的对象最终会在没有引用它们时被垃圾回收,假设您的代码片段在全局范围内,这是真的,当然如果您的 var 声明在函数内,一旦功能已经退出。一个例外是闭包,其中局部范围内的对象仍然由函数返回的变量引用。
我在上面提到了 'eventually' 垃圾收集,因为实际收集对象时会受到各种因素(内存压力等)的影响,这特定于 JavaScript 引擎(V8、chakra、nitro等)正在使用。
您的想法是正确的,但需要注意一些细微之处:
首先,JavaScript 运行 时间决定了何时真正 运行 垃圾收集例程。未使用的对象被标记为垃圾收集,不会立即被收集。 GC 可能非常昂贵,因此它不会 运行 持续。
其次,当一个对象变成 unreachable 时,它就有资格进行 GC,而不是简单地没有引用。
如果 GC 只考虑引用计数,您可以创建 "closed loop" 无法访问、无法收集的对象。
考虑这个片段:
var owner = { name: 'Ann' }; // Let's call this object 'Ann'
var pet = { name: 'Zizi' }; // And this one 'Zizi'
// create a loop of references
owner.pet = pet;
pet.owner = owner;
owner = null; // owner no longer refers to Ann
pet = null; // pet no longer refers to Zizi
当此代码完成 运行ning 时,没有对 Zizi
或 Ann
的顶级引用 - 它们是 unreachable 。在现代 运行 时代(就像您的浏览器中的时代),它们被标记为 GC 并将在下一个 运行s GC 例程时被清理。
但是,如果仅当对象的引用计数达到零时才收集对象怎么办?让我们考虑一下Zizi
。无法收集它,因为 Ann
仍然有对它的引用。它无法使用,因为没有可用的引用。
Ann
也收不到,因为Zizi
又引用了。这是一个糟糕的情况——用户代码无法访问两个对象,但也无法对其进行垃圾回收。这是内存泄漏。
这种称为引用计数的垃圾收集算法在旧版本的 Internet Explorer 中导致 infamous issue:DOM 节点和事件处理程序可以防止彼此被垃圾收集。由于这个原因,引用计数垃圾收集器在很大程度上已经过时了。
MDN 有一篇关于 memory management 的非常好的文章。并且专门讨论了内存分配和垃圾回收,并给出了很多例子。
我有一个关于垃圾收集在 Javascript 中如何工作的快速问题。
如果我有这个代码:
var c = {name : ‘Bob’};
c = {name : ‘Mary’};
在上面的代码中,变量 c 指向对象 {name : 'Bob'}。但后来我将 c 设置为指向内存中的另一个对象 {name : 'Mary'}。 c 最初指向的对象 ({name : 'Bob'}) 会怎样?由于不再有对它的引用,是否会在内存中释放该原始对象?
另一种情况:
var c = {name : ‘Bob’};
d = c;
c = {name : ‘Mary’};
现在,c 指向的原始对象 ({name : 'Bob'}) 不会被释放,因为即使 "c" 更改后 d 仍指向 {name : 'Bob'}指向新对象:{name : 'Mary'}。正确吗?
所以基本上一个对象不会从内存中释放,只要有引用仍然指向它。
如果我的想法正确,有人可以向我解释一下吗?
正确的对象最终会在没有引用它们时被垃圾回收,假设您的代码片段在全局范围内,这是真的,当然如果您的 var 声明在函数内,一旦功能已经退出。一个例外是闭包,其中局部范围内的对象仍然由函数返回的变量引用。
我在上面提到了 'eventually' 垃圾收集,因为实际收集对象时会受到各种因素(内存压力等)的影响,这特定于 JavaScript 引擎(V8、chakra、nitro等)正在使用。
您的想法是正确的,但需要注意一些细微之处:
首先,JavaScript 运行 时间决定了何时真正 运行 垃圾收集例程。未使用的对象被标记为垃圾收集,不会立即被收集。 GC 可能非常昂贵,因此它不会 运行 持续。
其次,当一个对象变成 unreachable 时,它就有资格进行 GC,而不是简单地没有引用。
如果 GC 只考虑引用计数,您可以创建 "closed loop" 无法访问、无法收集的对象。
考虑这个片段:
var owner = { name: 'Ann' }; // Let's call this object 'Ann'
var pet = { name: 'Zizi' }; // And this one 'Zizi'
// create a loop of references
owner.pet = pet;
pet.owner = owner;
owner = null; // owner no longer refers to Ann
pet = null; // pet no longer refers to Zizi
当此代码完成 运行ning 时,没有对 Zizi
或 Ann
的顶级引用 - 它们是 unreachable 。在现代 运行 时代(就像您的浏览器中的时代),它们被标记为 GC 并将在下一个 运行s GC 例程时被清理。
但是,如果仅当对象的引用计数达到零时才收集对象怎么办?让我们考虑一下Zizi
。无法收集它,因为 Ann
仍然有对它的引用。它无法使用,因为没有可用的引用。
Ann
也收不到,因为Zizi
又引用了。这是一个糟糕的情况——用户代码无法访问两个对象,但也无法对其进行垃圾回收。这是内存泄漏。
这种称为引用计数的垃圾收集算法在旧版本的 Internet Explorer 中导致 infamous issue:DOM 节点和事件处理程序可以防止彼此被垃圾收集。由于这个原因,引用计数垃圾收集器在很大程度上已经过时了。
MDN 有一篇关于 memory management 的非常好的文章。并且专门讨论了内存分配和垃圾回收,并给出了很多例子。