[V8] Fix memory leaks with weak handles

This commit is contained in:
Mikhail Lobotskiy
2025-05-29 16:56:17 +04:00
parent ae71fefd92
commit 29c01ac9c9
2 changed files with 39 additions and 3 deletions

View File

@ -220,6 +220,34 @@ namespace NSJSBase
m_internal->m_context.Clear(); m_internal->m_context.Clear();
} }
} }
class WeakHandleVisitor : public v8::PersistentHandleVisitor
{
private:
WeakHandleVisitor() = default;
public:
void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t class_id) override
{
if (class_id == CJSEmbedObjectPrivate::kWeakHandleId)
{
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> handle = value->Get(isolate).As<v8::Object>();
v8::Local<v8::External> field = v8::Local<v8::External>::Cast(handle->GetInternalField(0));
CJSEmbedObject* native = static_cast<CJSEmbedObject*>(field->Value());
delete native;
}
}
public:
static WeakHandleVisitor* getInstance()
{
static WeakHandleVisitor visitor;
return &visitor;
}
};
void CJSContext::Dispose() void CJSContext::Dispose()
{ {
#ifdef V8_INSPECTOR #ifdef V8_INSPECTOR
@ -228,7 +256,13 @@ namespace NSJSBase
#endif #endif
m_internal->m_contextPersistent.Reset(); m_internal->m_contextPersistent.Reset();
m_internal->m_isolate->Dispose(); // destroy native object in the weak handles before isolate disposal
v8::Isolate* isolate = m_internal->m_isolate;
{
v8::Isolate::Scope scope(isolate);
isolate->VisitHandlesWithClassIds(WeakHandleVisitor::getInstance());
}
isolate->Dispose();
m_internal->m_isolate = NULL; m_internal->m_isolate = NULL;
} }

View File

@ -900,6 +900,8 @@ namespace NSJSBase
{ {
public: public:
v8::Persistent<v8::Object> handle; v8::Persistent<v8::Object> handle;
// contstant id for all weak native handles
static const uint16_t kWeakHandleId = 1;
CJSEmbedObjectPrivate(v8::Local<v8::Object> obj) CJSEmbedObjectPrivate(v8::Local<v8::Object> obj)
{ {
@ -918,6 +920,8 @@ namespace NSJSBase
handle.Reset(CV8Worker::GetCurrent(), obj); handle.Reset(CV8Worker::GetCurrent(), obj);
handle.SetWeak(pEmbedObject, EmbedObjectWeakCallback, v8::WeakCallbackType::kParameter); handle.SetWeak(pEmbedObject, EmbedObjectWeakCallback, v8::WeakCallbackType::kParameter);
// set class_id for being able to iterate over all these handles to destroy them on isolate disposal
handle.SetWrapperClassId(kWeakHandleId);
pEmbedObject->embed_native_internal = this; pEmbedObject->embed_native_internal = this;
} }
@ -931,8 +935,6 @@ namespace NSJSBase
static void EmbedObjectWeakCallback(const v8::WeakCallbackInfo<CJSEmbedObject>& data) static void EmbedObjectWeakCallback(const v8::WeakCallbackInfo<CJSEmbedObject>& data)
{ {
v8::Isolate* isolate = data.GetIsolate();
v8::HandleScope scope(isolate);
CJSEmbedObject* wrap = data.GetParameter(); CJSEmbedObject* wrap = data.GetParameter();
((CJSEmbedObjectPrivate*)wrap->embed_native_internal)->handle.Reset(); ((CJSEmbedObjectPrivate*)wrap->embed_native_internal)->handle.Reset();
delete wrap; delete wrap;