为什么迭代 Set 的值会分配并产生垃圾?
Why does iterating over a Set's values allocate and create garbage?
昨天我问 如何在不分配的情况下迭代 Map
。 v8 开发人员回复如下:
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 文件的脚本标签中:
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 Memory
列,您会看到内存随时间缓慢增长。
但是,如果您注释行 setInterval(setIterate, 1);
并取消注释行 setInterval(arrayIterate, 1);
并刷新页面,您将看到内存使用量保持不变。
也就是说,遍历 Set
随着时间的推移会产生垃圾堆积,而遍历数组则不会。
有什么方法可以迭代 Set 而不会随着时间的推移产生这种垃圾堆积?我正在开发一个浏览器游戏并在我的渲染循环中迭代许多 Sets
和 Maps
并且由于 GC 运行.
偶尔会出现帧峰值
Why does iterating over a Set's values allocate and create garbage?
没有。使用 --trace-gc
(在 d8
或 node
中)对 setIterate
进行一百万次调用显示零 activity。 如果函数每次迭代分配一个字节(它不能;最小分配粒度是两个指针,即8个字节),那么年轻一代至少会填满那个时候有过一次。
Is there any way to iterate a Set without producing this garbage build-up over time?
当然;例如你是怎么做的。
why does the Task Manager show memory increasing over time?
我不认为它会那样做。我已经完全按原样复制粘贴了您的代码片段,并让它静置几分钟;该选项卡的 Chrome 任务管理器的“JavaScript 内存”列没有变化一千字节。 (这实际上只能证明这个测试不是真正的压力测试:一旦 sum
超过 1<<30
,它 将 开始疯狂分配,但这不是因为集合或数组...)
大胆猜测:也许您安装了一些扩展程序,将代码注入每个页面并导致分配?无论如何,无论它是什么,它都不是 for..of
循环 Set
s.
昨天我问 Map
。 v8 开发人员回复如下:
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 文件的脚本标签中:
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 Memory
列,您会看到内存随时间缓慢增长。
但是,如果您注释行 setInterval(setIterate, 1);
并取消注释行 setInterval(arrayIterate, 1);
并刷新页面,您将看到内存使用量保持不变。
也就是说,遍历 Set
随着时间的推移会产生垃圾堆积,而遍历数组则不会。
有什么方法可以迭代 Set 而不会随着时间的推移产生这种垃圾堆积?我正在开发一个浏览器游戏并在我的渲染循环中迭代许多 Sets
和 Maps
并且由于 GC 运行.
Why does iterating over a Set's values allocate and create garbage?
没有。使用 --trace-gc
(在 d8
或 node
中)对 setIterate
进行一百万次调用显示零 activity。 如果函数每次迭代分配一个字节(它不能;最小分配粒度是两个指针,即8个字节),那么年轻一代至少会填满那个时候有过一次。
Is there any way to iterate a Set without producing this garbage build-up over time?
当然;例如你是怎么做的。
why does the Task Manager show memory increasing over time?
我不认为它会那样做。我已经完全按原样复制粘贴了您的代码片段,并让它静置几分钟;该选项卡的 Chrome 任务管理器的“JavaScript 内存”列没有变化一千字节。 (这实际上只能证明这个测试不是真正的压力测试:一旦 sum
超过 1<<30
,它 将 开始疯狂分配,但这不是因为集合或数组...)
大胆猜测:也许您安装了一些扩展程序,将代码注入每个页面并导致分配?无论如何,无论它是什么,它都不是 for..of
循环 Set
s.