我有一个iterator defined in C++。典型迭代的代码路径基本上是:
NAN_METHOD(SharedMap::next) {
auto obj = Nan::New<v8::Object>();
info.GetReturnValue().Set(obj);
// ...
auto arr = Nan::New<v8::Array>();
arr->Set(0, Nan::New<v8::String>("key example").ToLocalChecked());
arr->Set(1, Nan::New<v8::String>("value example").ToLocalChecked());
Nan::Set(obj, Nan::New<v8::String>("value").ToLocalChecked(), arr);
}
我可以在JS端使用以下方法进行迭代:
for (let [key, value] of iteratorObject) {
console.log(`${key}: ${value}`)
}
如果我使用memwatch.HeapDiff()
检查此循环的每10000次迭代,则会看到change.details
如下:
"details": [
{
"what": "Array",
"size_bytes": 810344,
"size": "791.35 kb",
"+": 20151,
"-": 85
},
{
"what": "Object",
"size_bytes": 399368,
"size": "390.01 kb",
"+": 10001,
"-": 12
},
{
"what": "String",
"size_bytes": -144,
"size": "-144 bytes",
"+": 13,
"-": 27
},
{
"what": "TickObject",
"size_bytes": 560056,
"size": "546.93 kb",
"+": 10001,
"-": 0
}
}
这似乎意味着在每次循环迭代中有两个数组分配,一个对象分配和一个TickObject
分配。我不确定为什么没有匹配数量的字符串分配。我也不确定第二个数组分配来自哪里(可能来自解构吗?)。
如果我让该循环运行几百万个周期,我最终将用光内存(JS因堆错误而崩溃)。
当GC在该循环中运行时,如何确保可以回收为该循环的先前迭代所做的分配?