Javascript内存释放

时间:2015-10-17 21:29:32

标签: javascript garbage-collection

我有一个关于垃圾收集如何在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'}。正确的吗?

所以基本上只要存在仍然指向它的引用,对象就不会从内存中释放出来。

如果我正确地考虑这个问题,有人可以向我解释一下吗?

3 个答案:

答案 0 :(得分:2)

当没有对它们的引用时,最终正确的对象是垃圾收集,假设你的代码片段在全局范围内,这是真的,当然如果你的var声明在一个函数内,一旦函数有了它就会超出范围退出。一个例外是闭包,其中本地作用域上的对象仍由函数返回的变量引用。

我提到上面收集的'最终'垃圾,因为当实际收集的对象受到各种因素(内存压力等)的影响时,这是特定于正在使用的JavaScript引擎(V8,脉轮,硝基等)。

答案 1 :(得分:2)

你有正确的想法,但有一些细微之处需要注意:

首先,JavaScript运行时决定何时实际运行垃圾收集例程。未使用的对象标记为垃圾收集,而不是立即收集。 GC可能非常昂贵,因此它不会持续运行。

其次,当一个对象变为unreachable时,它就有资格获得GC,而不是简单地没有引用。

如果GC仅考虑引用计数,则可以创建一个"闭环"无法到达,无法收集的物品。

请考虑以下代码段:

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

当此代码完成运行时,没有对ZiziAnn的顶级引用 - 它们无法访问。在现代运行时(如浏览器中的运行时),它们被标记为GC,并且在下一次运行GC例程时将被清除。

但是,如果只在参考计数达到零时收集了对象呢?让我们考虑Zizi。它无法收集,因为Ann仍然有引用它。它无法使用,因为没有可用的引用。

Ann也无法收集,因为Zizi会引用它。这是一个糟糕的情况 - 用户代码无法访问两个对象,但也无法进行垃圾回收。这是一次内存泄漏。

这种垃圾收集算法,称为引用计数,在旧版本的Internet Explorer中导致infamous issue:DOM节点和事件处理程序可能会阻止彼此进行垃圾收集。由于这个原因,参考计数垃圾收集器基本上已经过时了。

进一步阅读:Chrome Devtools Docs - Memory 101

答案 2 :(得分:1)

MDN有一篇关于memory management的非常好的文章。它通过许多例子具体讨论了内存分配和垃圾收集。