Search code examples
v8embedded-v8

V8 Garbage Collection Differs For ObjectTemplates and Objects Created With Them


V8's garbage collection seems to easily clean up as it goes a Local<T> value where T anything stored in the Local, however if you create an ObjectTemplate and then create an instance of that Object, v8 will wait to clean up the memory. Consider the following example where the resident set size remains stable throughout program execution:

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();
}

Above, all we do is create a new Object in a loop, and then handle_scope goes out of scope and it looks like the Local values allocated are garbage collected right away as the residential set size remains steady. However, there is an issue when this object is created through an ObjectTemplate that is also created in the loop:

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();
}

Here, the resident set size increases linearly until an unnecessary amount of ram is used for such a small program. Just looking to understand what is happening here. Sorry for the long explanation, i tried to keep it short and to the point :p. Thanks in advance!


Solution

  • V8 assumes that ObjectTemplates are long-lived and hence allocates them in the "old generation" part of the heap, where it takes longer for them to get collected by a (comparatively slow and rare) full GC cycle -- if the assumption was right and they actually are long-lived, this is an overall performance win. Objects themselves, on the other hand, are allocated in the "young generation", where they are quick and easy to collect by the (comparatively frequent) young-generation GC cycles.

    If you run with --trace-gc you should see this explanation confirmed.