前言:在 Node.js 中我们有时候会使用 global.gc() 主动触发 gc 来测试一些代码,因为我们知道 V8 gc 的执行时机是不定的。但是可能很少同学知道 global.gc() 的实现,本文介绍一些在 V8 中关于这部分的实现。,了解 global.gc() 实现之前,首先看一下 V8 的 Extension 机制。Extension 机制用于拓展 V8 的能力。在 V8 初始化的过程中,V8::Initialize 会初始化 Extension 机制,具体在 Bootstrapper::InitializeOncePerProcess 中。,V8 通过 RegisterExtension 注册了多个 Extension。,执行完 Register 后就形成了一个 Extension 链表,RegisteredExtension 对象只是对 Extension 对象的简单封装,它内部持有 Extension 对象和一个链表 next 指针,另外还有一个全局的对象 first_extension_ 指向链表头部。注册完 Extension 后,接下来看看初始化 Extension 的逻辑。具体的调用链是 NewContext -> CreateEnvironment -> InvokeBootstrapper.Invoke -> Bootstrapper::CreateEnvironment -> InstallExtensions -> Genesis::InstallExtensions。,当启动 V8 的时候设置了 expose_gc 标记,那么就会执行 InstallExtension。,至此就完成了 Extension 的安装。接下来具体看一下 global.gc() 对应的具体实现。,Extension 是 Extension 机制的基类,从上面代码中我们可以大致了解到一个 Extension 需要实现什么。接着看 gc Extension 的实现。,在 bytecode-generator.cc 中有以下代码。,所以我们来看一下 GetNativeFunctionTemplate。,大致就是当我们执行 global.gc() 时就会执行 GCExtension::GC 函数。,从这个函数中我们可以知道,global.gc 函数是可以带参数的,参数可以控制 gc 是同步还是异步,还可以控制 gc 的类型,我们知道 V8 里针对不同的 space 有不同的 gc 策略。参数的具体函数使用可以参考。,继续看核心函数 InvokeGC。,InvokeGC 就是根据同步的参数去调 heap 对象的 gc 接口从而做不同类型的 gc 回收。这就是 global.gc 的大致实现。,除此之外,还有其他 Extension,我们也可以自己写拓展,不过有点限制的是需要在 V8 初始化时就设置需要安装的 Extension。例如我们可以设置 expose_statistics 标记,然后通过全局函数收集堆信息(不同的 V8 版本支持的不一样)。,另外 V8 内部也实现了一些 Extension,包括内置的和一些 Demo,有兴趣的同学可以自行查看。
© 版权声明
文章版权归作者所有,未经允许请勿转载。