Javascript 垃圾回收。创建对象和变量?

5

我目前正在使用Javascript开发一款游戏。经过一些测试,我开始注意到偶尔出现的延迟,只能是由GC引起的。我决定对其进行分析。结果显示,GC实际上是罪魁祸首:

GC Profile

我读到创建新对象会引起很多GC。我想知道像这样的代码:

var x = [];

由于Java中的原始类型不会创建垃圾,因此它也会创建任何垃圾。由于JavaScript中没有真正的类型,我不确定。此外,哪种方法可以创建最少的垃圾:

选项1:

function do() {
    var x = [];
    ...
}

选项2:
var x = [];
function do() {
    x = [];
    ...
}

选项3:
function do() {
    x = [];
    ...
}

或者选项4:

function do() {
    var x = [];
    ...
    delete x;
}

选项5:
var x = [];
function do() {
    x.length = 0;
    ...
}

在我的情况下,do函数每秒被调用30次。它对数组执行多个操作。

我想知道这个问题的答案,因为我刚刚将所有变量都设置为全局变量,以尝试防止它们被GC收集,但是GC并没有改变太多。

您能否提供一些常见的创建大量垃圾的事物和一些替代方案的示例。

谢谢。


1
不,Javascript中的基本类型不会创建任何垃圾对象。尽量将所有变量声明为局部变量,这样它们可以在最短时间内被清除(全局变量是一种灾难!)。尝试避免使用闭包和其他创建新对象的操作。请提供你遇到问题的实际代码。 - Bergi
3
首选选择选项1。选项4基本相同,只是最后有一个完全不必要的赋值。在使用delete的选项4中,不起作用,因为delete不会销毁对象。选项2和3执行完全不同的操作,您几乎不需要那样做 - 全局变量是反模式。 - Bergi
不,你的实际代码可能确实会执行某些操作。在你提供的片段中,你甚至没有执行 do。这些“模式”过于通用,无法对它们的GC行为提供任何有用的信息。do 是否经常被执行或者是否在热路径上?在计算出 x 后,还有其他地方/方式在哪里使用了它?目前很可能会受到死代码消除的影响,唯一的分配是为 do 函数对象和可能的 x 全局变量。 - Bergi
更新问题。我每秒钟调用do函数30次。 - user3011902
1
这篇博客文章也许会对你有所帮助:JavaScript游戏循环和时间控制的详细解释。还有一些关于编写快速、内存高效的JavaScriptJavaScript内存管理的文章。 - jkdev
显示剩余2条评论
1个回答

2
你能展示时间轴的内存情况吗?如果你的应用存在垃圾回收问题,那么在时间轴上会很明显地看到锯齿形波浪图。每当图形下降时,就是垃圾回收开始工作,阻塞您的线程以清空垃圾,这是与内存相关的冻结主要原因。
锯齿形波浪图示例(蓝色表示内存):enter image description here 一般来说,你所使用的对象实例化方式并不重要,因为 [] 的内存影响很小,你所关心的是数组的内容,但是让我们来看一下你的选项: 选项1: 这通常没问题,但有一个需要考虑的事情:闭包。你应该尽可能避免使用闭包,因为它们通常是垃圾回收的主要原因。 选项2: 避免引用超出你的范围之外的东西,这对内存并没有帮助,而且它会使你的应用程序变慢,因为必须沿闭包链去找匹配项。这样做没有任何好处。 选项3: 千万不要这样做,你总是希望将 x 定义在某个地方,否则你会故意泄漏到全局作用域中,因此它有可能永远无法被垃圾回收。 选项4: 这实际上是一个有趣的例子。通常 delete x 不起作用,因为 delete 仅作用于对象的属性。如果您不知道的话,delete 实际上返回一个布尔值,表示是否已删除对象,因此您可以在 Chrome 控制台中运行此示例:
function tmp () {
    var a = 1;
    delete a; // false
    console.log('a=', a) // 1

    b = 2;
    delete b; // true !!!
    console.log('b=', b) // Exception
}
tmp();

什么?!当你说b = 2(没有var)时,它与编写window.b = 2相同,因此当你使用delete b时,你基本上正在执行delete window.b,这满足“仅删除属性条款”。 不过,千万别这样做!
选项5:实际上,这个选项可以节省一点点内存,因为它不必GC x,但是:它必须GC x的所有内容,而这通常比x本身要大得多,因此不会有任何区别。
如果您想了解更多关于内存分析和常见的内存性能陷阱的信息,请参考这篇绝妙的文章:http://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接