v8: Как убедиться, что слабый обратный вызов работает на выходе?
У меня возникли проблемы с выполнением следующего кода. Это небольшое расширение материала, найденного по адресу https://github.com/v8/v8/wiki/Embedders-Guide. Он отличается тем, что у него есть конструктор для объекта, в дополнение к только объекту. Код будет успешно выполнен, однако утечка родного |PointAndPersistent| размещены в |PointConstructor|. Я попытался обеспечить обратный вызов для его очистки с помощью |SetWeak|, основываясь на некотором коде, который я нашел в d8 ( https://cs.chromium.org/chromium/src/v8/src/d8.cc?q=DataAndPersistent&sq=package:chromium&l=215), однако он никогда не выполняется. Кто-нибудь знает, как правильно это сделать?
#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 ответ
Слабые обратные вызовы вызываются, когда сборщик мусора определяет, что объект может быть освобожден. Кратковременная программа, подобная вашему примеру, не требует запуска сборщика мусора.
Вы можете попробовать принудительно запустить цикл GC, прежде чем завершать работу своего приложения. Конечно, это замедлит ваше отключение.
Для записи, документация SetWeak
говорит:
ПРИМЕЧАНИЕ. Нет гарантии относительно того, когда или даже будет вызван обратный вызов. Вызов выполняется исключительно на основе максимальных усилий. Как всегда, на завершение на основе GC не следует полагаться ни на какую критическую форму управления ресурсами!