可以将对象标记为不被垃圾收集吗?

时间:2013-12-27 18:52:07

标签: javascript garbage-collection

我不太了解JavaScript垃圾收集器,只是它试图管理引用,以便可以定期从内存中清除未引用的对象。如果语言实施者可行的话,我正在考虑一些我认为可以提高性能的东西。

它会像这样。在文件中添加一行:

"no gc";

这类似于use strict设置。它会将文件中定义的所有内容标记为不进行垃圾回收。我认为这将在jQuery和下划线等库中使用。所有辅助方法都将被标记并存储在不由GC管理的单独的内存区域中。

虽然我知道这可能最终会保留那些从未使用过的东西;它至少会将它与定期的GC过程隔离开来。因此,虽然我们可能会吞噬一些额外的内存,但至少可以减轻GC处理的负担。

我为这个建议的天真而道歉,因为我从未实施过GC。我只是想知道这个想法是否可行,或者JavaScript是否已经以某种方式解决了这个问题。

4 个答案:

答案 0 :(得分:3)

如果你想把它们保存为缓存,那么你就拥有了全局范围。

在浏览器中,全局范围是窗口,

因此,如果您不希望对象X永远不会收集垃圾,那么只需编写

即可
window.nogc = X;

因为全局范围的窗口将永远不会被垃圾收集,所以它的子引用也不会被垃圾收集,直到我们明确地进行。

答案 1 :(得分:2)

垃圾收集仅在线程空闲时运行。没有任何内容可以保存,因为只有在系统不忙时才会发生GC。

所以不,这是不可能的。

答案 2 :(得分:1)

您可以通过从GC根目录引用对象来确保不收集对象,但不能确保它不会被GC处理。

原因是JS VM中的GC通常通过Mark-and-Sweep或功能相同的方法实现。 GC的基本前提是经历一个如下的循环:

  1. GC将堆中的所有对象标记为"可能可用于发布"。这通常通过一个标志切换来完成,该标志切换改变了对象上现有标记的解释的含义"需要保持"到"安全释放"。因此,在此阶段不会对对象进行实际迭代。将GC告诉"不要标记"某些对象实际上需要额外的操作,而不是更少。

  2. GC从GC根开始,遍历参考树,更改对象标记,从#34;安全到释放"到"需要保持"。这是" Mark"相。 GC根可以是全局对象,当前正在执行的堆栈,事件循环上的挂起回调等。树遍历本身也可以以各种方式完成,DFS是最简单的。

  3. GC遍历堆中的所有对象,并删除任何仍然标记为"安全释放"。这是" Sweep"相。此阶段存在许多优化,这允许GC在单个操作中释放一组对象使用的内存。然而,这需要至少某种程度的迭代,而不是对象组,如果不是对象本身。

  4. 现在问题是设置"非GC"竞技场:假设你的"非GC"竞技场是引用一个普通的对象。期间" Mark"阶段,如果该对象未标记,则将被释放。这意味着你所有的"不可收集的"对象需要是GC根源才能保持"他们引用的常规对象。作为GC根目录,与GC根目录直接引用相比,没有任何性能优势。两者都必须平等地参与" Mark"相。

    唯一的替代方案是您的不可收藏物品根本无法强烈引用可收藏物品。这可以通过拥有自己的二进制堆而不是使用本机JS对象来实现。二进制数据不会被解释为引用,并且堆对象将在单个操作中完成其标记阶段。这就是asm.js的作用:它预先分配一个大型数组作为其内部堆。对于VM,整个数组都算作一个大对象,因此不会对在其中编码的任何数据结构进行垃圾回收。使用此方法确实存在将所有对象和数据结构编码为堆的二进制格式所需的缺陷,并在您想要使用它们时对其进行解码。使用asm.js时,这由编译器处理。

答案 3 :(得分:0)

在JavaScript中

如果要杀死对象,则必须删除所有引用。 假设我们有一个像这样的对象:

var myobj={ obj : {} };

我们想要GC的obj对象,我们必须这样做:

myobj["obj"] = null;
delete myobj["obj"];

但是如果你定义了另一个引用该对象的变量,它就不会被这些行杀死。例如,如果你这样做:

var obj = myobj.obj;

如果您确实要删除该对象,则对此变量执行相同的操作:

obj  = null;
delete obj;

然后如果没有参考就会被杀死。 换句话说,如果你想阻止你的对象来自GC,可以在某处创建一个引用并将其保密。