v8: 如何保证弱回调在退出时运行?

v8: How to ensure that weak callback runs at exit?

我在执行以下代码时遇到了一些问题。它是在 https://github.com/v8/v8/wiki/Embedders-Guide#accessing-dynamic-variables. It differs in that it has a constructor for the object, in addition to just the object. The code will run successfully, however will leak the native |PointAndPersistent| allocated in |PointConstructor|. I have attempted to provide a callback to clean it up with |SetWeak|, based on some code I found in d8 (https://cs.chromium.org/chromium/src/v8/src/d8.cc?q=DataAndPersistent&sq=package:chromium&l=215) 处找到的 material 的轻微扩展,但它从未执行过。有谁知道完成这个的正确方法是什么?

#include <cstdio>

#include "v8/include/libplatform/libplatform.h"
#include "v8/include/v8.h"

using namespace v8;

struct PointAndPersistent {
  int x;
  int y;
  Global<Object> wrapper;
};

void PointAndPersistentCallback(
    const WeakCallbackInfo<PointAndPersistent>& data) {
  data.GetParameter()->wrapper.Reset();
  delete data.GetParameter();
}

void PointConstructor(const FunctionCallbackInfo<Value>& args) {
  PointAndPersistent* point_and_persistent = new PointAndPersistent();
  if (args.Length() > 0) {
    point_and_persistent->x = args[0]->Int32Value();
  }
  if (args.Length() > 1) {
    point_and_persistent->y = args[1]->Int32Value();
  }

  point_and_persistent->wrapper.Reset(args.GetIsolate(), args.This());
  point_and_persistent->wrapper.SetWeak(point_and_persistent,
                                        PointAndPersistentCallback,
                                        v8::WeakCallbackType::kParameter);
  point_and_persistent->wrapper.MarkIndependent();

  args.This()->SetInternalField(0,
                                External::New(args.GetIsolate(), point_and_persistent));
  args.GetReturnValue().Set(args.This());
}

void GetPointX(Local<String> property,
               const PropertyCallbackInfo<Value>& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  int value = static_cast<PointAndPersistent*>(ptr)->x;
  info.GetReturnValue().Set(value);
}

void SetPointX(Local<String> property, Local<Value> value,
               const PropertyCallbackInfo<void>& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  static_cast<PointAndPersistent*>(ptr)->x = value->Int32Value();
}

void GetPointY(Local<String> property,
               const PropertyCallbackInfo<Value>& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  int value = static_cast<PointAndPersistent*>(ptr)->y;
  info.GetReturnValue().Set(value);
}

void SetPointY(Local<String> property, Local<Value> value,
               const PropertyCallbackInfo<void>& info) {
  Local<Object> self = info.Holder();
  Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
  void* ptr = wrap->Value();
  static_cast<PointAndPersistent*>(ptr)->y = value->Int32Value();
}

int main() {
  Platform* platform = platform::CreateDefaultPlatform();
  V8::InitializePlatform(platform);
  V8::Initialize();

  Isolate::CreateParams params;
  params.array_buffer_allocator = ArrayBuffer::Allocator::NewDefaultAllocator();
  Isolate* isolate = Isolate::New(params);
  {
    Isolate::Scope isolate_scope(isolate);
    HandleScope handle_scope(isolate);

    Local<FunctionTemplate> point_constructor_template =
        FunctionTemplate::New(isolate, PointConstructor);
    point_constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
    point_constructor_template->InstanceTemplate()->SetAccessor(
        String::NewFromUtf8(isolate, "x"), GetPointX, SetPointX);
    point_constructor_template->InstanceTemplate()->SetAccessor(
        String::NewFromUtf8(isolate, "y"), GetPointY, SetPointY);
    Local<ObjectTemplate> point_template =
        ObjectTemplate::New(isolate, point_constructor_template);

    Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
    Local<String> name =
        String::NewFromUtf8(isolate, "Point", NewStringType::kNormal)
            .ToLocalChecked();
    global_template->Set(name, point_constructor_template);
    Local<Context> context = Context::New(isolate, nullptr, global_template);
    Context::Scope context_scope(context);

    Local<String> source = String::NewFromUtf8(isolate, "new Point(1, 2).x;",
                                               NewStringType::kNormal)
                               .ToLocalChecked();
    Local<Script> script = Script::Compile(context, source).ToLocalChecked();
    Local<Value> result = script->Run(context).ToLocalChecked();
    String::Utf8Value utf8(isolate, result);
    printf("%s\n", *utf8);
  }

  isolate->Dispose();
  V8::Dispose();
  V8::ShutdownPlatform();
  delete platform;
  delete params.array_buffer_allocator;
}

谢谢!

当垃圾收集器确定对象可以被释放时,将调用弱回调。像您的示例这样的短 运行ning 程序不需要 运行 垃圾收集器。

您可以尝试在关闭您的应用之前强制执行 GC 循环。当然,这会使您的关机速度变慢。


郑重声明,SetWeakdocumentation 表示:

NOTE: There is no guarantee as to when or even if the callback is invoked. The invocation is performed solely on a best effort basis. As always, GC-based finalization should not be relied upon for any critical form of resource management!