我正在考虑使用V8作为一个项目的嵌入式JavaScript引擎,但我很难弄清楚如何管理本地C++对象的生存期。本实验旨在演示弱指针回调。
在下面代码的末尾,我调用v8::Persistent::SetWeak并安装一个回调。我想要的只是能够创建一个被调用的回调演示。
我半心半意地希望它会像让句柄超出作用域一样容易,但是下面的代码不会调用回调。我还在某个地方读到,调用Isolate::IdleNotificationDeadline可能会强制垃圾收集,但这也不起作用。
如何演示正在调用的弱指针回调?我想编写一些代码,以便在程序退出之前的某个时候调用cleanup函数。
显然,我很难理解如何正确地设置这个问题,并希望得到一些帮助和解释。恐怕我还不明白。
我的期望是,可以通过Persistent句柄创建弱指针,并且当对象没有句柄时,回调(最终)将被调用,以便释放与该JavaScript对象关联的本地C++资源。
v8.h头文件中的注释尤其让我感到不快:
注意:无法保证何时或是否调用回调。调用只在最大努力的基础上执行。与以往一样,基于GC的终结不应被依赖于任何关键形式的资源管理!
这使得整个引擎对于使用这种机制管理本机对象似乎毫无用处。但我确信至少有一些最小的人为场景,其中调用回调。
我的要求是,我能够编写一些JavaScript来分配一个对象,当没有对它的引用时,该对象最终将被释放。
foo = createFoo(); // creates a JavaScript object wrapping the native C++ Foo object.
doSomethingWith(foo); // do stuff with the Foo here
foo = null; // make sure there are no more JavaScript handles to the wrapper for the Foo object.
// After this point, I'm hoping V8 will eventually let me know that I can delete the native C++ Foo object我假设我实际上不需要执行任何JavaScript来演示弱指针和清理机制。我希望我可以创建一个Persistent句柄,然后安装弱回调,然后让它超出范围。我的假设似乎是错误的,或者我没有在这里证明这一点。
#include <iostream>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
class Foo {};
void cleanup(const v8::WeakCallbackInfo<Foo>& data)
{
std::cout << "Weak Callback called" << std::endl;
delete data.GetParameter();
}
int main(int argc, char* argv[]) {
std::cout << "Start..." << std::endl;
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new isolate and make it the current one
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, v8::ObjectTemplate::New(isolate));
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> obj = v8::ObjectTemplate::New(isolate)->NewInstance(context).ToLocalChecked();
v8::Persistent<v8::Object> persistent;
persistent.Reset(isolate, obj);
persistent.SetWeak(new Foo(), cleanup, v8::WeakCallbackType::kParameter);
}
isolate->IdleNotificationDeadline(1.0);
std::cout << "...Finish" << std::endl;
}注意:上面的代码示例应该按照构建了V8的世界示例的方式构建。
发布于 2020-06-23 20:09:37
对于一个精心设计的例子,调用isolate->LowMemoryNotification()应该可以做到这一点。不过,我不建议在生产中这样做,因为这是对CPU时间的巨大浪费(除非您的内存状况确实很低,因为OOM差点崩溃)。
除此之外,你发现的评论也成立。依赖对空闲对象的弱回调很好;不建议依赖它来管理关键和稀缺的资源。如果有问题的对象加起来很大,那么您应该酌情使用isolate->AdjustAmountOfExternalAllocatedMemory(...),让GC知道有什么东西需要释放。而且,您应该有自己的后备机制,以便在Isolate消失时清理所有东西(如果您没有终止整个进程,那么无论如何)。
https://stackoverflow.com/questions/62539339
复制相似问题