Puerts | 利用V8机制进行并行GC | Blurred code

Puerts | 利用V8机制进行并行GC

2024/04/13

LastMod:2024/04/13

Categories: JavaScript PuerTs UE

这里讨论的东西其实是利用v8的机制,所以理论上nodejs的也能用上。

Finalizer的性能问题和可靠性问题

在用脚本语言和宿主语言交互的时候,不可避免的会创建许多临时的js object对象,比如在ts里调用各种C++函数,返回的结果都必须包装为js object。

最早Puerts全部使用的是v8::PersistentBase::SetWeak的方法,这也是v8的hello world文档里讲的方法(https://v8.dev/docs/embed)。 它允许在C++里指向js object的Persistant handle并设置为WeakPtr,当这个WeakPtr是最后一个存在的reference的时候,v8会调用我们指定的callback来执行资源释放的操作。

它的问题主要是:

ArrayBuffer BackStoring

v8 8加入的新机制,允许创建一个v8::arrayBuffer的时候指定所需要的BackStoring,一个BackStoring代表一段raw内存,这段内存的声明周期会和这个v8::arrayBuffer绑定到一起,当这个v8::arrayBuffer被GC回收的时候,会执行用户指定的callback来释放这段内存。

这个方案的优势是:

结合两个方法

最早Puerts的实现是所有的对象都改成了由ArrayBuffer管理,但是后面发现了一个问题,就是虚幻的UObject/UStruct这种对象需要在主线程上保证线程安全,而ArrayBuffer的GC释放是在worker thread上,这就导致会在worker thread上触发U类的析构函数,这是不允许的。

再次思考:

我们可以把这两种机制结合起来,把需要在主线程上释放的对象用PersistentBase<T>::SetWeak管理,其他的对象用v8::arraybuffer管理。 由于我们无法判断一个类的析构函数是否是线程安全的,只能做的保守一点,对于POD的类型,我们可以用v8::arraybuffer管理,对于其他类型,我们用PersistentBase<T>::SetWeak管理。

Puerts去年合进去了这个PR Free POD UStruct on Worker Thread. Fix #1539 by BlurryLight · Pull Request #1576 · Tencent/puerts.