当关联的Javascript对象在V8中被垃圾回收时,如何释放封装的C++对象

How do you free a wrapped C++ object when associated Javascript object is garbage collected in V8?

本文关键字:对象 何释放 C++ 封装 释放 V8 Javascript 关联      更新时间:2023-10-16

V8的文档解释了如何创建包装C++对象的Javascript对象。Javascript对象保留一个指向C++对象实例的指针。我的问题是,假设你在堆上创建C++对象,当gc收集Javascript对象时,你如何获得通知,这样你就可以释放堆分配的C++对象?

技巧是创建一个Persistent句柄(链接到API引用的第二个项目符号:"Persistent句柄不在堆栈上,只有当您专门删除它们时才会删除……当您需要为多个函数调用保留对对象的引用时,或者当句柄生存期与C++作用域不对应时,请使用持久句柄。"),并在其上调用MakeWeak(),传递一个回调函数,该函数将进行必要的清理("当对对象的唯一引用来自弱持久句柄时,使用Persistent::MakeWeak可以使持久句柄变弱,以触发垃圾收集器的回调。"——也就是说,当所有"常规"句柄都超出范围时,以及垃圾收集器即将删除对象时)。

Persistent::MakeWeak方法签名为:

void MakeWeak(void* parameters, WeakReferenceCallback callback);

其中WeakReferenceCallback被定义为函数的指针,采用两个参数:

typedef void (*WeakReferenceCallback)(Persistent<Object> object,
                                      void* parameter);

这些都可以在v8.h头文件中找到,该文件与作为公共API的v8一起分发。

您希望传递给MakeWeak的函数清除Persistent<Object>对象参数,该参数将在作为回调调用时传递给它。可以忽略void* parameter参数(或者void* parameter可以指向一个C++结构,该结构包含需要清理的对象):

void CleanupV8Point(Persistent<Object> object, void*)
{
    // do whatever cleanup on object that you're looking for
    object.destroyCppObjects();
}
Parameter<ObjectTemplate> my_obj(ObjectTemplate::New());
// when the Javascript part of my_obj is about to be collected
// we'll have V8 call CleanupV8Point(my_obj)
my_obj.MakeWeak(NULL, &CleanupV8Point);

通常,如果垃圾收集的语言可以保存对语言引擎之外的资源(文件、套接字,或者在您的情况下是C++对象)的引用,那么您应该提供一个"关闭"方法来尽快释放该资源,而不必等到GC认为有必要销毁您的对象。

如果您的C++对象内存不足,而垃圾收集的对象只是一个引用,情况会更糟:您可能会分配数千个对象,而GC只看到几个KB的小对象,不足以触发收集;而C++方面正在与几十兆字节的过时对象作斗争。

在(对象或函数的)某个封闭范围内完成所有工作。然后,当您超出范围时,您可以安全地删除C++对象。GC不检查指针是否存在指向对象。