为什么遍历Set的值会分配并创建垃圾? [英] Why does iterating over a Set's values allocate and create garbage?
问题描述
昨天我问了这个问题关于如何遍历 Map
而不进行分配的信息.v8开发人员回复了以下内容:
Yesterday I asked this question on how to iterate over a Map
without allocating. A v8 developer replied with the following:
但是,如果您只想对值进行处理,则可以通过仅对值进行迭代来避免创建它:for(map.values()的v){...}不会分配任何short生命的对象.遍历map.keys()也是一样.
But if you're only interested in processing the values anyway, you can avoid it being created by iterating over just the values: for (let v of map.values()) {...} does not allocate any short-lived objects. The same is true for iterating over map.keys().
我正在尝试在测试中复制它,但是遇到了麻烦.这是我制作的一个演示,它再现了使用简单的 Set
遇到的问题.将以下代码粘贴到脚本标记中的空HTML文件中:
I'm trying to replicate this in a test but I'm having trouble. Here's a demo I made that reproduces the problem I'm having with a simple Set
. Paste the following code in an empty HTML file in its script tags:
let a = new Set([ 1, 2, 3, 4, 5 ]);
let b = [ 1, 2, 3, 4, 5 ];
let sum = 0;
function setIterate() {
for (let item of a.values()) {
sum += item;
}
}
function arrayIterate() {
for (let i = 0; i < b.length; i++) {
sum += b[i];
}
}
setInterval(setIterate, 1);
// setInterval(arrayIterate, 1);
如果打开此HTML文件,然后按 Shift + Escape
,则应打开Chrome任务管理器.如果再查看 Javascript内存
列,则会看到内存随着时间的推移而缓慢增长.
If you open this HTML file and then hit Shift+Escape
it should open the Chrome Task Manager. If you then look at the Javascript Memory
column, you'll see the memory slowly growing over time.
但是,如果您注释行 setInterval(setIterate,1);
并取消注释行 setInterval(arrayIterate,1);
并刷新页面,您将看到内存使用率保持不变.
However, if you comment the line setInterval(setIterate, 1);
and uncomment the line setInterval(arrayIterate, 1);
and refresh the page you'll see that the memory usage stays constant.
也就是说,遍历 Set
会随着时间的推移而产生垃圾堆积,而遍历数组则不会.
That is, iterating over a Set
produces garbage build-up over-time while iterating over an array does not.
是否有任何方法可以迭代Set,而不会随着时间的推移而产生此垃圾堆积?我正在开发一个浏览器游戏,并在渲染循环中迭代许多 Sets
和 Maps
,由于运行了GC,偶尔会出现帧峰值.
Is there any way to iterate a Set without producing this garbage build-up over time? I'm developing a browser game and iterating over many Sets
and Maps
in my render loop and getting occasional frame-spikes due to the GC running.
推荐答案
为什么迭代Set的值会分配并创建垃圾?
Why does iterating over a Set's values allocate and create garbage?
不是.使用-trace-gc
(在 d8
或 node
中)对 setIterate
进行一百万次调用显示活动为零.如果该函数在每次迭代中甚至分配了一个字节(它不能分配;最小分配粒度为两个指针,即8个字节),那么年轻一代将至少填充一次时间.
It doesn't. Doing a million calls to setIterate
with --trace-gc
(in d8
or node
) shows zero activity. If the function allocated even a single byte per iteration (which it can't; the minimum allocation granularity is two pointers, i.e. 8 bytes), then the young generation would have filled up at least once in that time.
有没有办法迭代Set而不随着时间的推移而产生这种垃圾堆积?
Is there any way to iterate a Set without producing this garbage build-up over time?
绝对;例如您的操作方式.
Absolutely; for example how you're doing it.
为什么任务管理器显示内存随时间增加?
why does the Task Manager show memory increasing over time?
我看不到这样做.我已按原样复制粘贴了您的代码段,并让其放置了几分钟."JavaScript内存"此选项卡的Chrome任务管理器列中的所有列都没有增加一千字节.(实际上,这仅证明该测试不是真正的压力测试:一旦 sum
超过 1<<<<< 30> code,它 就会开始疯狂分配>,但这不是因为集合或数组...)
I don't see it doing that. I've copy-pasted your snippet exactly as-is and let it sit for a couple of minutes; the "JavaScript memory" column of Chrome's task manager for that tab hasn't budged by a single kilobyte. (Which actually only proves that this test isn't really a stress test: it will start allocating like crazy once sum
exceeds 1<<30
, but that's not because of the set or the array...)
疯狂的猜测:也许您安装了一些扩展程序,可以将代码注入每个页面并引起分配?无论如何,它不是 Set
s上的 for..of
循环.
Wild guess: maybe you have some extension installed that injects code into every page and causes allocations? At any rate, whatever it is, it's not the for..of
-loops over Set
s.
这篇关于为什么遍历Set的值会分配并创建垃圾?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!