【问题标题】:How to handle variables in loops from functions and functions in regards to garbage collector?关于垃圾收集器,如何处理来自函数和函数的循环中的变量?
【发布时间】:2014-12-27 03:31:55
【问题描述】:

我正在尝试创建我的小粒子系统作为自学,以了解有关 javascript 的更多信息。虽然我不是一个完整的编程初学者,但我不是专业程序员。目前我正在尝试提高我对纯 JavaScript 的了解(因此我的代码中没有库)。

在阅读了 google 和其他许多人的文章后,我发现自己对垃圾收集感到困惑。根据文章,与我的程序相比,内存图表应该看起来更流畅,也不应该经常调用 GC。以下是来自谷歌浏览器开发者工具的截图链接。

有两件事我想问你,如果你能提供任何见解,我将不胜感激。

a/ 这种行为是否可能是在函数内部调用 var 以进行循环索引的结果?

例子:

function doSomething(args) {
for (var i = 0; i < arr.length; i++) {/*some code*/}
}

我的动画循环经常调用不同的函数(requestanimationframe)。你如何处理循环使用的这些变量(var i)? 将它们声明为全局变量?但是,如果您从不同的函数调用中获得嵌套循环,那将变得非常丑陋。

b/ 将函数分配给变量是否会影响内存堆栈(在运行时创建新函数)?

在一篇文章中,我发现将函数分配给变量会阻止在每次函数调用时创建新函数。 我尝试将所有函数分配给变量并以这种方式调用它们,但遗憾的是它并没有改变任何东西(性能、内存图表)。

我当前的整个小粒子系统的小提琴(下面的链接)带有测试场景。屏幕上大约有 8700 个粒子,使用我的超慢处理器,它以恒定的 32 fps 运行。 使用四核处理器,我可以根据设置获得 54-60 fps(如果我不将静止物体绘制为生成器、吸引器等,则为 60 fps)。

但是当我运行它时,我会周期性地感到轻微的波动,所以我想提高我的代码效率并对其进行调整。但是我发现的方法对我不起作用。幸运的是,从一开始我就在回收粒子对象,所以在达到上述 8700 个粒子之后,我几乎不会使用新的构造函数创建任何新对象。

所以我想请教您的建议。

非常感谢您阅读本文 :-)。

其他链接:

小提琴:http://jsfiddle.net/kwgp7kmh/1/

来自 chrome 开发工具的内存图表:http://postimg.org/image/wl7pm4zzp/

【问题讨论】:

  • 通常,您希望在 for 循环之外定义变量。提升它很容易,你可以做一些简单的事情,比如:jsfiddle.net/jmy05rxs/1 此外,for 循环会阻塞。如果您正在循环处理大量数据,您可能想要执行类似 setInterval 的操作(它将函数调用推出事件循环)。示例:jsfiddle.net/jmy05rxs/2
  • #1 - 过早的优化是对时间和复杂性的巨大浪费。 #2 - 如果你确实有一个你知道与 GC 相关的测量问题,你甚至可以考虑进行 GC 优化,并且你可以测量问题发生在哪里,并且可以测量对代码进行更改的效果。综上所述,将任何不必在循环中的代码移出循环。
  • 你也可以尝试使用console.time('some_id') / `console.timeEnd('some_id'); 来调试瓶颈。检查它:jsfiddle.net/TheIronDeveloper/jmy05rxs/3
  • 您的 unshift 操作可能会产生大量垃圾 - 在大多数实现中,将元素附加到数组(在本例中通过 push)比添加元素要快,其中后者可能需要分配一个新数组,然后是一个数组副本。参见unshiftthis comparisonpush。换句话说,如果可能,请尝试将您的 unshift 操作重构为 push 操作。

标签: javascript performance canvas garbage-collection


【解决方案1】:

每当遇到性能方面的问题时,请使用分析器。
在这里,我看到应该归咎于 action(),占用了 32% 的 CPU。
动作代码过于通用,但有 3 个单独的案例,这使得它难以阅读并降低其性能。通过写得更清楚,我从 32% CPU 到 3% CPU !!!!

// execute an action
// list: generate, attract, draw
function action(actions, arr, addParticles, arg2) {
    if (actions == 'draw') {
        for (var i = 0; i < arr.length; i++) {
            arr[i].draw();
        }
        return;
    } else if ('generate' in actions) {
        if (addParticles) {                
            var generators = actions['generate'];
            for (var i = 0; i < generators.length; i++) {
                 generators[i].generate(arr);
            }
        }
    }
    var attractors = actions['attract'];
    if (attractors) {
        for (var j = 0; j < attractors.length; j++) {
            for (var i = 0; i < data.lives; i++) {
                attractors[j].attract(arr[i]);
            }
        }
    }
    var repulsors = actions['repulse'];
    if (repulsors) {
        for (var j = 0; j < repulsors.length; j++) {
            for (var i = 0; i < data.lives; i++) {
                repulsors[j].repulse(arr[i], arg2);
            }
        }
    }
}

移动可以通过一些简单的缓存获得一点好处。

粒子的绘制是在更新(已修复)中完成的 + 其他一些修复使您的应用更加流畅:

http://jsfiddle.net/gamealchemist/kwgp7kmh/3/

编辑:
上面的代码要快得多,因为它将由 Javascript 引擎编译,假设(这是正确的)每个数组只包含相同类型的对象。所以成本会更接近于相同 C++ 代码的成本。
另一方面,在写作时:

 actions[prop][j][prop](arr[i], arg1, arg2); 

每次引擎将执行所有操作:读取propactions,检索prop[actions](1),检索其j-th元素(2),检索此元素的prop方法(3 ), 检索 arr[i] (4);然后调用 4 个无法使用类型假设进行优化的代价高昂的操作。您必须为引擎编写一个非常“明显”的代码才能对其进行优化。

【讨论】:

  • 我看到,即使您在函数中添加了 var,但在阅读上述文章后,它并没有导致我害怕的任何事情。起初我将动作写成单独的案例,但在添加了更多不同的对象后,我将其更改为通用的。这些天我已经习惯了分析器。非常感谢您花在这方面的所有时间,它对我的​​帮助比我预期的要多!
  • 情绪化:哇。就像真的哇。没想到有人会仔细阅读代码,甚至把它做得更好。当我还是个孩子的时候,我终于发现了我父母在“解剖”他们花了这么多时间为我准备的食物时的感受。不过,与他们不同,我真的很感激! :-)。非常感谢!
  • var 需要时间,但没有什么比这四个方向的动作[prop][j][prop](arr[i], arg1, arg2);你在你的一个 for 循环中做。您可以在这里查看github.com/gamealchemist/JSparkle,了解我为优化粒子引擎所做的最大努力。很高兴您欣赏我的剖析,祝您编码愉快!
  • 天哪,太快了,太快了!这需要一段时间才能爬上去,感谢您的链接做得很好:-)。
  • 致 GameAlchemist:最后一个问题。 actions[prop][j][prop](arr[i], arg1, arg2) 到底有什么问题。我认为更多的过热来自 for (var prop in actions),因为它强制循环遍历整个对象并检查 ownProperty,当我知道我在寻找什么时,这对于执行每个函数调用似乎是多余的。但我不明白你所说的'.. 4 undirections of ..'是什么意思?你能帮我扩展一下吗?非常感谢。
猜你喜欢
  • 2012-03-21
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 2012-03-16
  • 1970-01-01
  • 2012-03-16
  • 2021-05-01
相关资源
最近更新 更多