前言:在Node.js中,我们有时会使用global.gc()主动触发gc来测试一些代码,因为我们知道V8的执行时序gc不确定。但是可能很少有同学知道global.gc()的实现。本文介绍这部分在V8中的一些实现。在了解global.gc()的实现之前,先看看V8的Extension机制。Extension机制用于扩展V8的能力。在V8初始化的过程中,V8::Initialize会初始化Extension机制,具体在Bootstrapper::InitializeOncePerProcess中。voidBootstrapper::InitializeOncePerProcess(){v8::RegisterExtension(std::make_unique(GCFunctionName()));v8::RegisterExtension(std::make_unique());v8::RegisterExtension(std::make_unique());v8::RegisterExtension(std::make_unique());v8::RegisterExtension(std::make_unique());}V8通过RegisterExtension注册多个Extension。voidRegisterExtension(std::unique_ptrextension){RegisteredExtension::Register(std::move(extension));}voidRegisteredExtension::Register(std::unique_ptrextension){RegisteredExtension*new_extension=newRegisteredExtension(std::move(扩展名));new_extension->next_=first_extension_;first_extension_=new_extension;}执行Register后,形成一个Extension链表。RegisteredExtension对象只是对Extension对象的简单封装,它持有Extension对象和一个链表next指针,以及一个指向链表头部的全局对象first_extension_。注册完Extension,我们再看一下初始化Extension的逻辑。具体调用链为NewContext->CreateEnvironment->InvokeBootstrapper.Invoke->Bootstrapper::CreateEnvironment->InstallExtensions->Genesis::InstallExtensions。boolGenesis::InstallExtensions(Isolate*isolate,Handlenative_context,v8::ExtensionConfiguration*extensions){ExtensionStatesextension_states;returnInstallAutoExtensions(isolate,&extension_states)&&(!FLAG_expose_gc||InstallExtension(isolate,"v8/gc",&extension_states))}当V8启动时设置了expose_gc标志,就会执行InstallExtension。boolGenesis::InstallExtension(Isolate*isolate,v8::RegisteredExtension*current,ExtensionStates*extension_states){HandleScope作用域(isolate);extension_states->set_state(current,VISITED);v8::Extension*extension=current->extension();//安装依赖项for(inti=0;idependency_count();i++){if(!InstallExtension(isolate,extension->dependencies()[i],extension_states)){returnfalse;}}//编译扩展CompileExtension(isolate,extension);extension_states->set_state(current,INSTALLED);returntrue;}至此,Extension的安装就完成了。接下来我们看一下global.gc()的具体实现。classV8_EXPORTExtension{public:Extension(constchar*name,constchar*source=nullptr,intdep_count=0,constchar**deps=nullptr,intsource_length=-1);虚拟~Extension(){删除source_;}virtualLocalGetNativeFunctionTemplate(Isolate*isolate,Localname){returnLocal();}constchar*name()const{returnname_;}size_tsource_length()const{返回source_length_;}constString::ExternalOneByteStringResource*source()const{returnsource_;}intdependency_count()const{returndep_count_;}constchar**dependencies()const{returndeps_;}voidset_auto_enable(boolvalue){auto_enable_=value;}boolauto_enable(){返回auto_enable_;}//禁止复制和分配。扩展(常量扩展&)=删除;voidoperator=(constExtension&)=delete;私人:常量字符*名称_;size_tsource_length_;//预期在source_String::ExternalOneByteStringResource*source_之前初始化;intdep_count_;constchar**deps_;布尔auto_enable_;};Extension是Extension机制的基类。从上面的代码中,我们可以大致了解一个Extension需要实现什么然后再看gcExtension的实现。类GCExtension:publicv8::Extension{public:explicitGCExtension(constchar*fun_name):v8::Extension("v8/gc",BuildSource(buffer_,sizeof(buffer_),fun_name)){}v8::LocalGetNativeFunctionTemplate(v8::Isolate*isolate,v8::Localname)覆盖;staticvoidGC(constv8::FunctionCallbackInfo&args);private:staticconstchar*BuildSource(char*buf,size_tsize,constchar*fun_name){base::SNPrintF(base::Vector(buf,static_cast(size)),"本机函数%s();",有趣的名字);返回缓冲区;}charbuffer_[50];};bytecode-generator.cc中有如下代码。v8::Localinfo=expr->extension()->GetNativeFunctionTemplate(v8_isolate,Utils::ToLocal(expr->name()));那么让我们来看看GetNativeFunctionTemplate。首先看GetNativeFunctionTemplate。```cv8::LocalGCExtension::GetNativeFunctionTemplate(v8::Isolate*isolate,v8::Localstr){returnv8::FunctionTemplate::New(isolate,GCExtension::GC);}大致意思就是GCExtension::GC这个函数会在我们执行global.gc()的时候执行。voidGCExtension::GC(constv8::FunctionCallbackInfo&args){v8::Isolate*isolate=args.GetIsolate();//没有参数则同步执行kFullGarbageCollectiongc,即执行global.gc()时if(args.Length()==0){InvokeGC(isolate,ExecutionType::kSync,v8::Isolate::GarbageCollectionType::kFullGarbageCollection);返回;}automaybe_options=Parse(isolate,args);如果(maybe_options.IsNothing())返回;GCOptionsoptions=maybe_options.ToChecked();//否则根据参数处理switch(options.execution){caseExecutionType::kSync:InvokeGC(isolate,ExecutionType::kSync,options.type);休息;caseExecutionType::kAsync:{v8::HandleScope范围(隔离);自动解析器=v8::Promise::Resolver::New(isolate->GetCurrentContext()).ToLocalChecked();args.GetReturnValue().Set(resolver->GetPromise());autotask_runner=V8::GetCurrentPlatform()->GetForegroundTaskRunner(iso晚的);CHECK(task_runner->NonNetableTasksEnabled());task_runner->PostNonNetableTask(std::make_unique(isolate,resolver,options.type));}休息;}}从这个函数我们可以知道,global.gc函数是可以带参数的。参数可以控制gc是同步还是异步,也可以控制gc的类型。我们知道V8对于不同的空间有不同的gc策略参数。具体功能用法可以参考。在调用|fun_name|(options)时提供垃圾收集,其中options是一个类似字典的对象。请参阅下面支持的属性。-没有参数引用选项:{type:'major',execution:'sync'}。-没有设置任何选项的真实参数:{type:'minor',execution:'sync'}。支持的选项:-type:'major'or'minor'forfullGCandScavenge,respective.-execution:'sync'or'async'forsynchronousandasynchronousexecution,respectively.-默认为{type:'major',execution:'同步'}。返回一个Promise,当请求异步执行时GC完成时resolve,否则为undefined。继续看核心函数InvokeGC。voidInvokeGC(v8::Isolate*isolate,ExecutionTypeexecution_type,v8::Isolate::GarbageCollectionTypetype){Heap*heap=reinterpret_cast(isolate)->heap();开关(类型){casev8::Isolate::GarbageCollectionType::kMinorGarbageCollection:heap->CollectGarbage(i::NEW_SPACE,i::GarbageCollectionReason::kTesting,kGCCallbackFlagForced);休息;案例v8::Isolate::GarbageCollectionType::kFullGarbageCollection:EmbedderStackStateScopestack_scope(heap,execution_type==ExecutionType::kAsync?EmbedderStackStateScope::kImplicitThroughTask:EmbedderStackStateScope::kExplicitInvocation,execution_type==ExecutionType::kAsync?v8::EmbedderHebedder:State::kNoHeapPointers:v8::EmbedderHeapTracer::EmbedderStackState::kMayContainHeapPointers);堆->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,i::GarbageCollectionReason::kTesting,kGCCallbackFlagForced);休息;}}InvokeGC是根据同步参数调整堆对象的gc接口,做不同类型的gc回收。这是global.gc的大致实现。此外,还有其他的Extensions,我们也可以自己写extension,但是有一个限制,需要在V8初始化的时候设置要安装的Extensions。比如我们可以设置expose_statistics标志,然后通过全局函数收集堆信息(不同V8版本支持不同)。node-expose_statistics-e"console.log(global.getV8Statistics())"此外,V8内部还实现了一些Extension,包括内置的和一些Demo。感兴趣的同学可以自行查看。