2017-04-21 27 views
0

我正在創建純C++對象(僅限於C++),然後將它們附加到作爲API包裝器實例返回的JS-暴露對象。附件的方式是通過SetInternalField存儲的External::New - 幾乎完全遵循V8 Embedder's Guide中列出的模式。如何清理本地<External>引用中跟蹤的C++對象?

這些對象旨在由JS進行內存管理,但即使在刪除JS中的引用並觸發垃圾回收後,C++對象仍然存在。析構函數沒有被調用,如果我在別處保存了獨立的引用,它仍然有效。

我覺得V8的本地值清除不知道如何(或是否)破壞void*的內容,但這不是一個突出的用例嗎?我無法找到任何方式來解決一般外部人員或當地人的解除範圍/清理問題。此外,任何我使用persist(如MakeWeak)做的事情都不會影響在JS端無法訪問的本地人(對吧?)。

如何確保這些C++對象在包含它們的JS包裝對象超出範圍時最終(最好立即)被銷燬?得到數據傳遞給JS


實例實例:

Local<Value> createWindow(HWND handle, Isolate* isolate) { 
    // Build an instance from a premade FunctionTemplate with object 
    // and method prototypes, and SetInternalFieldCount(1) 
    Local<Function> fn = Local<Function>::New(isolate, window); 

    constructingInternally = true; 
    Local<Object> obj = fn->NewInstance(Context::New(isolate)).ToLocalChecked(); 
    constructingInternally = false; 

    CppWindow* win = CppWindow(handle); 
    lastWin = win; // added for debugging 
    obj->SetInternalField(0, External::New(isolate, win)); 
    return obj; 
} 

更新:多小時盲目,審判和錯誤的猜測後,我終於有編譯代碼和當對象被垃圾收集時觸發的回調。嘗試在回調中使用Local<External>;或包含Local<Object>;的時間很長,因爲我無理由理解,這些嘗試會拒絕編譯帶有令人困惑的錯誤(例如「Local <External>'has no member'Value' 「或」'Local <Object>'has no member'GetInternalField'「)。當他們最終編譯完成後,在嘗試訪問我的對象的過程中,這個過程會在回調中靜靜地死去。最終我醒悟過來並通過一個直接指向該對象的指針,我現在可以直接刪除它。

Local<Value> createWindow(HWND handle, Isolate* isolate) { 
    Local<Function> fn = Local<Function>::New(isolate, window); 

    constructingInternally = true; 
    Local<Object> obj = fn->NewInstance(Context::New(isolate)).ToLocalChecked(); 
    constructingInternally = false; 

    CppWindow* win = CppWindow(handle); 
    obj->SetInternalField(0, External::New(isolate, win)); 

    Persistent<Object>(isolate, obj).SetWeak(
     win, 
     [](const WeakCallbackInfo<CppWindow>& data) { 
      delete data.GetParameter(); 
     }, 
     WeakCallbackType::kParameter 
    ); 

    return obj; 
} 

在任何地方都沒有一個代碼示例表明這個簡單明瞭的用例完全是犯罪。第二個鏈接jmrk提供了至少允許我將最終需要的一些模糊線索拼湊在一起,但這些來源幾乎與C++新手有相同的誤導。

回答

0

正確,V8無法神奇地猜測你的C++對象存在,或者如何釋放它們。

解決此問題的常用方法是使用Persistents。對於弱持久句柄,可以設置一個回調函數,當V8釋放對象的最後一個引用時將調用該回調函數。在該回調中,您可以調用釋放任何相關C++對象所需的任何析構函數。

如果您可以預測它們的生命週期(例如,取決於您的應用程序在做什麼,「正在處理某個請求」或某些情況下),則可能的替代方案是自己管理對象。該選項可能會更快,可能會更容易實現, - 或者可能是不可能的,如果您無法預測對象的生命週期。

+0

是否有任何最新的指南/代碼示例顯示如何執行此操作?我一直無法弄清楚如何使用與JS交互的方式使用persist,直到我確信它們不是以這種方式使用,至少在最近的(6.x)版本的節點中。 – HonoredMule

+0

'd8'外殼中有一個例子:https://chromium.googlesource.com/v8/v8/+/master/src/d8.cc#2000以及V8的API測試中的更多:https:// chromium .googlesource.com/v8/v8/+/master/test/cctest/test-api.cc(查找「SetWeak」的出現次數)。 – jmrk