簡體   English   中英

了解節點插件 API (N-API) HandleScope

[英]Understanding Node Addon API (N-API) HandleScope

我很難理解如何正確使用HandleScopeEscapableHandleScope 例如,從這個節點示例

MyObject::MyObject(const Napi::CallbackInfo& info) : Napi::ObjectWrap<MyObject>(info) {
  Napi::Env env = info.Env();
  Napi::HandleScope scope(env);

  this->val_ = info[0].As<Napi::Number>().DoubleValue();
};

為什么在這種情況下我們需要創建一個新的 HandleScope ? 這個另一個例子

Napi::Object CreateObject(const Napi::CallbackInfo& info) {
  Napi::Env env = info.Env();
  Napi::Object obj = Napi::Object::New(env);
  obj.Set(Napi::String::New(env, "msg"), info[0].ToString());

  return obj;
}

為什么這里不需要?

另外,我沒有找到任何使用 EscapableHandleScope 的例子,什么時候需要這個?

以下似乎適用於 nan、N-API 和 node-addon-api:

[Handle Scope] 是一種抽象,用於控制和修改在特定范圍內創建的對象的生命周期。 通常,N-API 值是在句柄范圍的上下文中創建的。 當從 JavaScript 調用本機方法時,將存在默認句柄范圍。 如果用戶未明確創建新的句柄范圍,則將在默認句柄范圍中創建 N-API 值。 對於本地方法執行之外的任何代碼調用(例如,在 libuv 回調調用期間),模塊需要在調用任何可能導致創建 JavaScript 值的函數之前創建一個范圍。

來源: https : //nodejs.org/api/n-api.html#n_api_napi_handle_scope

這意味着在給出的示例中,由於兩者都期望const Napi::CallbackInfo& info很明顯兩者都是從 JavaScript 直接調用的,因此它們已經具有由 JS 運行時提供的作用域——僅在需要時才需要額外調用創建作用域自己執行內存管理,或者在您的代碼獨立於 JS 引擎執行的情況下(例如在計時器上,來自 JS 代碼以外的其他東西的回調等)

有關 HandleScopes 是什么以及它們的用途的解釋,請參閱V8 的文檔,例如類Local

有兩種類型的句柄:本地句柄和持久句柄。

本地句柄是輕量級和瞬態的,通常用於本地操作。 它們由 HandleScopes 管理。 這意味着 HandleScope 在創建時必須存在於堆棧中,並且它們僅在創建期間處於活動狀態的 HandleScope 內有效。 要將本地句柄傳遞給外部 HandleScope,必須使用 EscapableHandleScope 及其 Escape() 方法。

對於類HandleScope

管理多個本地句柄的堆棧分配類。 創建句柄范圍后,將在該句柄范圍內分配所有本地句柄,直到刪除該句柄范圍或創建另一個句柄范圍。 如果已經有一個句柄作用域並且創建了一個新的句柄作用域,則所有分配都將在新的句柄作用域中進行,直到它被刪除。 之后,新的句柄將再次在原始句柄范圍內分配。

刪除本地句柄的句柄范圍后,垃圾收集器將不再跟蹤存儲在句柄中的對象,並可能將其解除分配。 訪問已刪除句柄范圍的句柄的行為是未定義的。

務實:

  • 當從 JavaScript 調用到 C++ 時,如果 C++ 代碼創建了任何Local<> s,則至少需要一個HandleScope 通常正好一個HandleScope是正確的數字。
  • 創建和銷毀 HandleScopes 是有成本的,所以如果你有很多細粒度的 HandleScopes,你就是在浪費時間。 另一方面, HandleScope (按照設計,這就是它的目的!)保持其中包含的句柄所指的所有對象都處於活動狀態(在 GC 意義上),因此對於非常長時間運行的代碼,或具有多次迭代的循環,您可能希望引入短暫的 HandleScopes,以便可以釋放您完成的臨時對象。
  • 正如文檔所說,如果您想在范圍的生命周期結束后返回一個對象,則需要一個EscapableHandleScope

為什么我們需要在代碼片段中創建一個新的 HandleScope?

其實這里我們可以選擇不創建新的 HandleScope 。 Node.js 中有一個外部作用域,它包含在此函數中創建的句柄。 但是,在此函數中創建的所有句柄將比所需的壽命更長,並處理成本資源。

我們什么時候需要 EscapableHandleScope?

當來自內部作用域的句柄需要超過該作用域的生命周期時。 例如,當返回函數中新創建的數據時。

參考

V8 嵌入: https : //v8.dev/docs/embed#handles-and-garbage-collection

node-addon-api: https://github.com/nodejs/node-addon-api/blob/master/doc/object_lifetime_management.md

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM