您现在的位置是:亿华云 > 人工智能

一篇带给你 V8 global.gc() 的实现

亿华云2025-10-03 15:56:17【人工智能】6人已围观

简介前言:在 Node.js 中我们有时候会使用 global.gc() 主动触发 gc 来测试一些代码,因为我们知道 V8 gc 的执行时机是不定的。但是可能很少同学知道 glob

前言:在 Node.js 中我们有时候会使用 global.gc() 主动触发 gc 来测试一些代码,篇带因为我们知道 V8 gc 的篇带执行时机是不定的。但是篇带可能很少同学知道 global.gc() 的实现,本文介绍一些在 V8 中关于这部分的篇带实现。

了解 global.gc() 实现之前,篇带首先看一下 V8 的篇带 Extension 机制。Extension 机制用于拓展 V8 的篇带能力。在 V8 初始化的篇带过程中,V8::Initialize 会初始化 Extension 机制,篇带具体在 Bootstrapper::InitializeOncePerProcess 中。篇带

void Bootstrapper::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。篇带

void RegisterExtension(std::unique_ptrextension) {

RegisteredExtension::Register(std::move(extension));

}

void RegisteredExtension::Register(std::unique_ptrextension) {

RegisteredExtension* new_extension = new RegisteredExtension(std::move(extension));

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。

bool Genesis::InstallExtensions(Isolate* isolate,

Handlenative_context,

v8::ExtensionConfiguration* extensions) {

ExtensionStates extension_states;

return InstallAutoExtensions(isolate, &extension_states) &&

(!FLAG_expose_gc || InstallExtension(isolate, "v8/gc", &extension_states))

}

当启动 V8 的时候设置了 expose_gc 标记,那么就会执行 InstallExtension。

bool Genesis::InstallExtension(Isolate* isolate,

v8::RegisteredExtension* current,

ExtensionStates* extension_states) {

HandleScope scope(isolate);

extension_states->set_state(current, VISITED);

v8::Extension* extension = current->extension();

// 安装依赖

for (int i = 0; i < extension->dependency_count(); i++) {

if (!InstallExtension(isolate, extension->dependencies()[i],

extension_states)) {

return false;

}

}

// 编译 Extension

CompileExtension(isolate, extension);

extension_states->set_state(current, INSTALLED);

return true;

}

至此就完成了 Extension 的安装。接下来具体看一下 global.gc() 对应的具体实现。

class V8_EXPORT Extension {

public:

Extension(const char* name, const char* source = nullptr, int dep_count = 0,

const char** deps = nullptr, int source_length = -1);

virtual ~Extension() { delete source_; }

virtual LocalGetNativeFunctionTemplate(

Isolate* isolate, Localname) {

return Local();

}

const char* name() const { return name_; }

size_t source_length() const { return source_length_; }

const String::ExternalOneByteStringResource* source() const {

return source_;

}

int dependency_count() const { return dep_count_; }

const char** dependencies() const { return deps_; }

void set_auto_enable(bool value) { auto_enable_ = value; }

bool auto_enable() { return auto_enable_; }

// Disallow copying and assigning.

Extension(const Extension&) = delete;

void operator=(const Extension&) = delete;

private:

const char* name_;

size_t source_length_; // expected to initialize before source_

String::ExternalOneByteStringResource* source_;

int dep_count_;

const char** deps_;

bool auto_enable_;

};

Extension 是 Extension 机制的基类,从上面代码中我们可以大致了解到一个 Extension 需要实现什么。接着看 gc Extension 的实现。

class GCExtension : public v8::Extension {

public:

explicit GCExtension(const char* fun_name)

: v8::Extension("v8/gc", BuildSource(buffer_, sizeof(buffer_), fun_name)) { }

v8::LocalGetNativeFunctionTemplate(

v8::Isolate* isolate, v8::Localname) override;

static void GC(const v8::FunctionCallbackInfo& args);

private:

static const char* BuildSource(char* buf, size_t size, const char* fun_name) {

base::SNPrintF(base::Vector(buf, static_cast(size)),

"native function %s();", fun_name);

return buf;

}

char buffer_[50];

};

在 bytecode-generator.cc 中有以下代码。

v8::Local<v8::FunctionTemplate> info = expr->extension()->GetNativeFunctionTemplate(v8_isolate, Utils::ToLocal(expr->name()));

所以我们来看一下 GetNativeFunctionTemplate。

首先看 GetNativeFunctionTemplate。

```c

v8::LocalGCExtension::GetNativeFunctionTemplate(

v8::Isolate* isolate, v8::Localstr) {

return v8::FunctionTemplate::New(isolate, GCExtension::GC);

}

大致就是当我们执行 global.gc() 时就会执行 GCExtension::GC 函数。

void GCExtension::GC(const v8::FunctionCallbackInfo& args) {

v8::Isolate* isolate = args.GetIsolate();

// 没有参数则同步执行 kFullGarbageCollection gc,即执行 global.gc() 时

if (args.Length() == 0) {

InvokeGC(isolate, ExecutionType::kSync,

v8::Isolate::GarbageCollectionType::kFullGarbageCollection);

return;

}

auto maybe_options = Parse(isolate, args);

if (maybe_options.IsNothing()) return;

GCOptions options = maybe_options.ToChecked();

// 否则根据参数处理

switch (options.execution) {

case ExecutionType::kSync:

InvokeGC(isolate, ExecutionType::kSync, options.type);

break;

case ExecutionType::kAsync: {

v8::HandleScope scope(isolate);

auto resolver = v8::Promise::Resolver::New(isolate->GetCurrentContext())

.ToLocalChecked();

args.GetReturnValue().Set(resolver->GetPromise());

auto task_runner =

V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate);

CHECK(task_runner->NonNestableTasksEnabled());

task_runner->PostNonNestableTask(

std::make_unique(isolate, resolver, options.type));

} break;

}

}

从这个函数中我们可以知道,global.gc 函数是可以带参数的,参数可以控制 gc 是同步还是异步,还可以控制 gc 的类型,服务器租用我们知道 V8 里针对不同的 space 有不同的 gc 策略。参数的具体函数使用可以参考。

Provides garbage collection on invoking |fun_name|(options), where

- options is a dictionary like object. See supported properties below.

- no parameter refers to options:

{ type: major, execution: sync}.

- truthy parameter that is not setting any options:

{ type: minor, execution: sync}.

Supported options:

- type: major or minor for full GC and Scavenge, respectively.

- execution: sync or async for synchronous and asynchronous execution,

respectively.

- Defaults to { type: major, execution: sync}.

Returns a Promise that resolves when GC is done when asynchronous execution

is requested, and undefined otherwise.

继续看核心函数 InvokeGC。

void InvokeGC(v8::Isolate* isolate, ExecutionType execution_type,

v8::Isolate::GarbageCollectionType type) {

Heap* heap = reinterpret_cast(isolate)->heap();

switch (type) {

case v8::Isolate::GarbageCollectionType::kMinorGarbageCollection:

heap->CollectGarbage(i::NEW_SPACE, i::GarbageCollectionReason::kTesting,

kGCCallbackFlagForced);

break;

case v8::Isolate::GarbageCollectionType::kFullGarbageCollection:

EmbedderStackStateScope stack_scope(

heap,

execution_type == ExecutionType::kAsync

? EmbedderStackStateScope::kImplicitThroughTask

: EmbedderStackStateScope::kExplicitInvocation,

execution_type == ExecutionType::kAsync

? v8::EmbedderHeapTracer::EmbedderStackState::kNoHeapPointers

: v8::EmbedderHeapTracer::EmbedderStackState::

kMayContainHeapPointers);

heap->PreciseCollectAllGarbage(i::Heap::kNoGCFlags,

i::GarbageCollectionReason::kTesting,

kGCCallbackFlagForced);

break;

}

}

InvokeGC 就是根据同步的参数去调 heap 对象的 gc 接口从而做不同类型的 gc 回收。这就是 global.gc 的大致实现。

除此之外,还有其他 Extension,我们也可以自己写拓展,不过有点限制的是需要在 V8 初始化时就设置需要安装的 Extension。例如我们可以设置 expose_statistics 标记,然后通过全局函数收集堆信息(不同的 V8 版本支持的不一样)。

node -expose_statistics -e "console.log(global.getV8Statistics())"

另外 V8 内部也实现了一些 Extension,包括内置的和一些 Demo,有兴趣的同学可以自行查看。亿华云

很赞哦!(386)