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

时间:2017-10-10 03:01:23

标签: v8 embedded-v8

我在制作以下代码时遇到了一些麻烦。它是https://github.com/v8/v8/wiki/Embedders-Guide#accessing-dynamic-variables处发现的材料的略微延伸。它的不同之处在于它除了对象之外还有对象的构造函数。代码将成功运行,但会泄漏本机| PointAndPersistent |在| PointConstructor |中分配。我试图根据我在d8(https://cs.chromium.org/chromium/src/v8/src/d8.cc?q=DataAndPersistent&sq=package:chromium&l=215)中找到的一些代码,使用| SetWeak |来提供回调来清理它,但它永远不会被执行。有谁知道实现这个目标的正确方法是什么?

#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;
}

谢谢!

1 个答案:

答案 0 :(得分:0)

当垃圾收集器确定可以释放对象时,将调用弱回调。像你的例子一样的短期运行程序不需要运行垃圾收集器。

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

对于记录,SetWeak的{​​{3}}说:

  

注意:无法保证何时甚至如果回调是    调用。调用仅在尽力而为的基础上执行。    与往常一样,基于GC的终结应该依赖于任何    资源管理的关键形式!