【发布时间】:2021-08-04 06:30:15
【问题描述】:
我正在用 Javascript 开发一款游戏,其中涉及尽快运行渲染循环。我注意到 GC(垃圾收集器)峰值中断了平滑的帧速率,并且在分析后我发现我的实体查询系统正在生成大量垃圾。
在这样做的过程中,我在 Javascript 中发现了 iterators cause allocations。在我的代码的一部分中,我正在做这样的事情:
let minimumSet = this.getSmallestEntitySet(componentTypes);
for (let entity of minimumSet) {
// handle entity
}
不幸的是,只是执行for of 循环会导致分配(因为它每次运行循环时都会创建一个新的迭代器对象),并且由于它经常运行,因此会产生大量垃圾。我环顾四周,不知道是否有办法在不执行分配的情况下迭代Set、Map 或Object。例如,使用 Javascript 数组,您可以迭代它,同时避免像这样的分配:
for (let i = 0; i < arr.length; i++) {
let item = arr[i];
// handle item
}
但我找不到像这样只使用常规 for 循环来迭代 Map 或 Set 的方法。有可能吗?
假设这是不可能的,我假设解决方法是使用排序数组而不是映射,对吗?唯一的问题是插入和删除是O(log n) 而不是O(1),但我想这可能是值得的,只是为了避免分配。
这是我最好的选择,有没有一种方法可以在不执行分配的情况下迭代这些集合?
【问题讨论】:
-
你怎么知道迭代器对垃圾负责?从您自己的链接来看,优秀的 JS 引擎会优化此类循环中涉及的所有对象,以支持直接迭代底层容器的后备存储。
-
@ShadowRanger 您可以通过运行一个紧密循环来确定这一点,其中一个使用
for of,另一个使用标准for,并分析Chrome 任务管理器@987654335 中的Javascript memory列@。或者,您也可以使用 Chrome 分析器在开发者工具的Memory选项卡中分析分配情况。 -
对我来说听起来像是 V8 回归。
-
"有可能吗?" - 没有。
-
我想到了一个解决方案。我会发布一个答案。
标签: javascript performance iterator set v8