V8 的文档解释了如何创建包装 C++ 对象的 Javascript 对象。Javascript 对象持有指向 C++ 对象实例的指针。我的问题是,假设您在堆上创建了 C++ 对象,当 Javascript 对象被 gc 收集时,如何获得通知,以便释放堆分配的 C++ 对象?
3 回答
诀窍是创建一个Persistent
句柄(链接到 API 参考中的第二个要点:“Persistent
句柄不保存在堆栈上,只有在您专门删除它们时才会被删除。......当您需要保留一个对多个函数调用的对象的引用,或者当句柄生命周期不对应于 C++ 范围时。”),并调用MakeWeak()
它,传递一个回调函数,该函数将进行必要的清理(“可以使持久句柄变弱,当对对象的唯一引用来自弱持久句柄时,使用Persistent::MakeWeak
, 触发垃圾收集器的回调。” - 也就是说,当所有“常规”句柄都超出范围并且垃圾收集器即将删除目的)。
Persistent::MakeWeak
方法签名是:
void MakeWeak(void* parameters, WeakReferenceCallback callback);
whereWeakReferenceCallback
被定义为一个指向函数的指针,带有两个参数:
typedef void (*WeakReferenceCallback)(Persistent<Object> object,
void* parameter);
这些可以在与 V8 作为公共 API 一起分发的 v8.h 头文件中找到。
您希望传递给的函数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 不检查指针是否存在指向对象。