V8 垃圾收集因 ObjectTemplate 和使用它们创建的对象而异

V8 Garbage Collection Differs For ObjectTemplates and Objects Created With Them

V8 的垃圾收集似乎很容易清理,因为它有一个 Local<T> 值,其中 T 存储在 Local 中的所有内容,但是如果您创建一个 ObjectTemplate 并且然后创建那个 Object 的实例,v8 将等待清理内存。考虑以下示例,其中驻留集大小在整个程序执行期间保持稳定:

Isolate* isolate = Isolate::New(create_params);
Persistent<Context> *context= ContextNew(isolate); // creates a persistent context

for(int i = 1 ; i <= 1000000; i ++ ) {
    isolate->Enter();
    EnterContext(isolate, context); // enters the context 
    {
        HandleScope handle_scope(isolate);
        Local<Object> result = Object::New(isolate);
    }
    ExitContext(isolate, context);
    isolate->Exit();
}

上面,我们所做的就是在循环中创建一个新的 Object,然后 handle_scope 超出范围,看起来分配的 Local 值被垃圾收集了离开,因为住宅集的大小保持稳定。但是,当通过也在循环中创建的 ObjectTemplate 创建此对象时会出现问题:

Isolate* isolate = Isolate::New(create_params);
Persistent<Context> *context= ContextNew(isolate); // creates a persistent context

for(int i = 1 ; i <= 1000000; i ++ ) {
   isolate->Enter();
   EnterContext(isolate, context); // enters the context 
   {
       HandleScope handle_scope(isolate);
       Local<Object> result;
       Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
       if (!templ->NewInstance(context->Get(isolate)).ToLocal(&result)) { exit(1); }
   }
   ExitContext(isolate, context);
   isolate->Exit();
}

这里,驻留集大小线性增加,直到不必要的内存量被用于这样一个小程序。只是想了解这里发生了什么。抱歉,我的解释很长,我尽量保持简短并切中要点:p。提前致谢!

V8 假定 ObjectTemplates 是 long-lived,因此将它们分配在堆的 "old generation" 部分,在那里它们需要更长的时间才能被(相对较慢且罕见的)完整 GC 收集循环——如果假设是正确的并且它们实际上是 long-lived,这就是整体性能的胜利。另一方面,对象本身分配在 "young generation" 中,在那里它们可以通过(相对频繁的)young-generation GC 周期快速轻松地收集。

如果你 运行 使用 --trace-gc 你应该看到这个解释得到确认。