【发布时间】: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)比添加元素要快,其中后者可能需要分配一个新数组,然后是一个数组副本。参见unshift的this comparison 与push。换句话说,如果可能,请尝试将您的unshift操作重构为push操作。
标签: javascript performance canvas garbage-collection