日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

N-API的JS堆對象生命周期管理

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 2023-12-29 09:41 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

N-API的JS堆對象生命周期管理

N-API是Node API的簡寫,同時也是nodejs的JS VM(鏈)接入原生模塊.node文件的應用程序二進制接口(i.e. ABI)。借助N-API引入的抽象隔離,升級nodejs運行時(虛擬機)

【編譯】不要求對原生擴展模塊重新編譯— 為nodejs的不同版本分別準備不同的原生模塊build真的好麻煩。

【運行】不導致原生模塊程序崩潰— 精讀每一版changelogs清單和微調原生模塊源碼更耗時費力。

N-API開放接口在nodejs 10+后才逐步穩(wěn)定,和成為nodejs c-addon的主流編程標準。 不久前,我有機會在工程實踐中獨立完成“給node-webkit容器編寫原生擴展模塊的”程序開發(fā)任務。雖然擴展模塊自身的業(yè)務處理邏輯很簡單 — 餒餒的“膠水”代碼,但其涉及到了跨越多個FFI接口調用的JS對象緩存處理。初版程序緩存不住JS堆內存中的變量值,因為JS VM的GC總是在FFI接口調用的間隙回收由原生模塊緩存的JS對象和導致程序崩潰。由此,我特意“死磕”C/C++ addons with Node-API廠方文檔,在解決工程難題的同時匯總實踐收獲寫下此文。 文章以名詞解釋統(tǒng)一術語理解開篇,以對比不同版本ABI標準引題,以技術細節(jié)展開討論為依據(jù),最后向讀者圖文并茂地描述我個人創(chuàng)新的實踐方案。

名詞解釋

nodejs c-addon

nodejs原生擴展模塊。所謂“原生”是相對JS模塊而言的。它必須由【系統(tǒng)編程語言C / Cpp / Rust】編寫,并經(jīng)由nodejs開放接口N-API,

接入nodejs的JS VM,并

與nodejs交換數(shù)據(jù)·互操作。

為了文字簡練,下文也將其記作為addon。 nodejs c-addon與Commonjs Module在科技樹上處于相同的生態(tài)位,和對“上游”調用端的JS業(yè)務代碼呈現(xiàn)一致的調用方式。

JS堆對象

它既包括由JS程序自身構造的對象實例,也包含由系統(tǒng)程序從addon內調用N-API接口(比如,napi_create_object())實例化的JS對象。它們都

被保存在JS VM的內存中,和

被Rust內存中的napi_value可修改原始指針引用。

N-API引用計數(shù)

它是指向JS堆對象的“FFI引用計數(shù)”智能指針(后文有圖,應該會更直觀些)。其

被保存于JS VM的內存中,和

被Rust內存中的napi_ref可修改原始指針引用。即,addon端Rust程序拿到的是指向了“智能指針”的“指針”。

被用于阻止JS VM的GC回收正活躍于addon端的JS堆對象。這就賦予了 @Rustacean 從JS VM外部干預JS對象生命周期的能力。React Native可都做不到這一點。

WASM墊片程序

它既包括由wasm-bindgen-cli生成的JS墊片程序文件,也包含由wasm-bindgen crate導出的Rust開發(fā)框架。正是js <-> Rust兩端墊片程序的協(xié)同配合,JS堆對象才幾乎被“投影為”Rust所有權(棧)變量。比如,JS堆對象的wasm_bindgen::JsValue(智能指針)結構體就比nj_sys::napi_value可修改原始指針更能發(fā)揮Rust類型系統(tǒng)與Borrow / Drop Checker對程序正確性的保障力。沒有“黑魔法”,滿眼都是對墊片程序開發(fā)迭代的工作量。

WASM vs. N-API堆對象生命周期管理策略

簡單地講,生命周期策略的差異取決于【墊片程序】的“薄/厚”。因為WASM應用場景多(包括但不限于:網(wǎng)頁、nodejs,wasm-runtime獨立虛擬機),社區(qū)關注度高,wasm-bindgen工具鏈迭代速度快,所以,wasm <-> js墊片程序就“厚”。JS堆對象向Rust的“投影”就更像【智能指針】,而不是“裸奔的”原始指針。WebAssembly工作組甚至規(guī)劃將墊片程序逐步“固化”至wasm-runtime內(比如,TC39弱引用提案與引用類型提案等)以完備核心功能。工作量到位自然對接平滑!這不是黑魔法,而是真金白銀的血汗努力。 相反,nodejs c-addon的應用場景就要少得多了。所以,技術社區(qū)鮮有熱情面向N-API開放接口編寫功能豐富的addon <-> js墊片程序。于是,@Rustacean 不得不直面

“裸奔的”原始指針

簡陋的Rust Bindings— 與C頭文件概念對等的Rust語言項

“安慰劑”式的編程工具。因為缺乏了js墊片程序的協(xié)同呼應,幾個Rust宏也只是杯水車薪,能“糖”的內容很少。

轉移更多精力從【業(yè)務邏輯實現(xiàn)】至【FFI編程】,并與各種FFI技術細節(jié)做“斗爭”。趕快補課內存布局理論知識去吧!

具體地講,在Rust - WASM程序上下文中,披上了“智能指針”馬甲的JS堆對象幾乎完全“銹化”了。@Rustacean 可忽視JS VM垃圾收集器的干擾和:

static全局緩存JS堆對象。而不必擔心活躍于addon的JS堆對象會被JS VM的GC回收。

相對FFI函數(shù)的單次調用執(zhí)行周期,延長JS堆對象的生命周期。

{ .. }塊作用域限定JS堆對象,按需釋放不再訪問的變量值,提高內存利用效率。就有局部變量的函數(shù)而言,這可明顯地降低JS堆內存占用的瞬時峰值。

相對FFI函數(shù)的單次調用執(zhí)行周期,縮短JS堆對象的生命周期

另一方面,N-API沒有功能面面俱到的墊片程序。所以,@Rustacean 做不到僅憑Rust基本語法項就對FFI另一端的JS堆對象執(zhí)行【全局緩存】或【塊作用域】按需回收的程序處理。甚至(重點來了),即便JS端代碼刻意保留了已FFI導出堆對象的引用,addon端(棧內存)所持有的原始指針依舊會,在FFI函數(shù)執(zhí)行之后,丟失其原本指向的值和成為“野”指針。我懷疑JS VM就算沒有回收也至少挪動了被導出JS堆對象的內存位置。由此,@Rustacean 需要在addon業(yè)務代碼中額外實現(xiàn)部分本該由墊片程序完成的“公共服務”功能,包括但不限于:

徒手維護N-API引用計數(shù)智能指針,以“鎖住”JS堆對象不被JS VM的GC回收 —延長JS堆對象的生命周期。

調用N-API程序接口構造可層疊嵌套的作用域【塊】 —縮短JS堆對象的生命周期。

這的確是一次接觸底層“自己動手豐衣足食”的機會,但絕對不是什么令人愉快的開發(fā)體驗。千言萬語匯聚一張圖(左側WASM,右側nodejs c-addon)促成讀者思緒的豁然開朗:

051c66a8-a585-11ee-8b88-92fbcf53809c.png

N-API JS堆對象生命周期管理的技術細節(jié)

addon對JS堆對象生命周期的管理分為如下三種情況(看圖吧,一圖抵千詞):

053d16a0-a585-11ee-8b88-92fbcf53809c.png

由上圖可見,真實數(shù)據(jù)被保存于JS端(堆)內存中。Rust端(棧)內存僅持有隨時可能失效的原始指針。所以,@Rustacean 需要調用特定的N-API接口,遠程操控JS堆對象的活躍周期。但是,N-API接口并不易用。這表現(xiàn)為...

N-API引用計數(shù)智能指針不智能

沒有RAII Guard對活躍引用數(shù)量的自動跟蹤。@Rustacean 還需書面編寫N-API接口調用和人工增減引用個數(shù)跟蹤引用復本數(shù)量 — 這是傳統(tǒng)的缺陷產(chǎn)出“大戶”。

引用數(shù)量意味著GC回收。@Rustacean 還需顯式地析構掉N-API【引用計數(shù)】智能指針實例,才能促使被“持久化于內存”的JS堆對象接受GC回收。否則,內存泄漏!具體作法請參見如下偽碼


use ::{napi_delete_reference, napi_reference_unref}; use ::napi_call_result; let result = Box::into_raw(Box::new(u32::MAX)); // 1. 將引用計數(shù)值減一 napi_call_result!(napi_reference_unref( , , result // 引用計數(shù)減一之后的結果數(shù)值 )).unwrap(); let result = unsafe { Box::from_raw(result) }; // 2. 判斷減一后的最新引用計數(shù)值是否已經(jīng)歸零。 if *result == 0 { // 當且僅當不再有任何 N-API 引用復本還指向該 JS 堆對象時, // 3. 顯式地釋放引用計數(shù)智能指針實例。 napi_call_result!(napi_delete_reference( // 這一步是必須的。要不然,內存就漏了! ,  )).unwrap(); }

只有四類JS堆對象支持N-API引用計數(shù)。它們分別是

napi_object—ECMAScript規(guī)范中的Object

napi_function—ECMAScript規(guī)范中的Function

napi_symbol—ECMAScript規(guī)范中的Symbol

napi_external— 類似于ECMAScript中的Blob,專門引用進程外的某種“黑盒opaque”資源。

若多個N-API引用計數(shù)指針實例(注:不是引用復本)都指向同一個JS堆對象,那么只有當全部N-API引用計數(shù)指針實例都被napi_delete_reference()處理后,“持久化于內存”的JS堆對象才被允許GC回收。

可逃逸作用域與作用域提升不實用

在上圖中的(普通)作用域napi_handle_scope禁止其內部的JS堆對象溢出作用域,和向外傳值。即,普通作用域是“多入無出”的。 【可逃逸作用域napi_escapable_handle_scope】有限松綁了這條限制。它允許作用域像函數(shù)一樣向外輸出一個且僅一個值,而輸出形式不是Rust塊表達式【返回值】,而是JS堆對象【作用域·提升handle promoting】。類比JS動態(tài)語言的【變量提升variable hoisting】,

相同點:塊內聲明的變量可從塊外引用和訪問

不同點:【可逃逸作用域】有且只有一個塊內聲明的變量可從塊外被訪問。否則,程序崩潰。

所以,可逃逸作用域是“多入單出”的面向實用有限放開。再看圖吧,一圖抵千詞!

055e7b7e-a585-11ee-8b88-92fbcf53809c.png

在作用域層疊嵌套的場景下,這絕對是“盛產(chǎn)”缺陷的泥沼。@Rustacean 需要從程序設計之初就努力避免從Rust端遠程管理JS變量的作用域。最好從產(chǎn)品架構上,多用addon構建【業(yè)務組件】,少封裝【功能模塊】,從根本上規(guī)避Rust <-> JS復雜互操作出現(xiàn)。

智能化N-API引用計數(shù) — “二段式”引用計數(shù)優(yōu)化法

相比于最低也需要【過程宏】作為抽象工具才能描述清楚的JS堆對象作用域,N-API引用計數(shù)智能化改造還是有捷徑可走的。 簡單地講,將對引用復本數(shù)量變化的跟蹤任務委托給遵循RAII with Guard設計模式的智能指針std::Rc處理。然后,addon業(yè)務實現(xiàn)代碼僅需負責

【始】調用napi_create_reference()接口,構造一個單復本引用計數(shù)指針實例,鎖住JS堆對象不被GC回收。

【末】調用napi_reference_unref()與napi_delete_reference()接口,清空引用復本與析構唯一的引用計數(shù)指針實例,解鎖GC回收JS堆對象。

接著看圖,依舊一圖抵千詞!

0577ae78-a585-11ee-8b88-92fbcf53809c.png

于是,整個設計方案的“難點”就聚焦于:

監(jiān)聽智能指針std::Rc的引用復本清空事件,并

在事件處理函數(shù)內,調用napi_reference_unref()與napi_delete_reference()接口通知VM GC回收JS堆對象。

難點不難,因為Newtypes設計模式允許 @Rustacean

對std::Rc做AOP編程。以

“攔截+重寫”std::Rc的析構函數(shù)::drop(&mut self)。于是,

在每個引用復本的析構處理后,都重新統(tǒng)計剩余引用復本的數(shù)量。最后,

沒有剩余引用復本了,就立即調用N-API接口napi_reference_unref()與napi_delete_reference()。

文章寫得再自恰也不如呈現(xiàn)一段既注釋豐富又可獨立運行的參考實現(xiàn)[例程]來得清晰明白。整個例程由四個部分組成:

模塊nj_sys模擬nj_sys crate的部分導出項,因為nj_sys crate并沒有入選playground.org的top 100熱門依賴包榜單。

模塊napi_rc包含了對智能指針std::Rc的AOP封裝。

函數(shù)napi_export_method()模仿nodejs c-addon的FFI導出函數(shù)。

入口函數(shù)main()模仿JS程序調用Rust-FFI函數(shù)napi_export_method()。

“二段式”引用計數(shù)優(yōu)化方案的裨益

【程序性能】將FFI調用次數(shù)減少至一個常量3。

【代碼健壯性】將引用復本的數(shù)量跟蹤任務從易錯的人工完成轉為機器自動完成。addon業(yè)務代碼僅需關注引用復本的個數(shù)歸零事件。

結束語

關于nodejs c-addon技術方向,我這次僅準備了上述偏【編程】內容與大家分享。其實,交叉編譯與動態(tài)庫鏈接也是一項可以聊出些許深度的話題。比如,如何做到“從一個工程,一個分支,一套Rust程序同時編譯出三版.node鏈接庫文件,以分別適用于nodejs / nwjs / electron三款應用程序容器”的呢?。哎!無處不是“黑科技” — 從條件編譯,至編譯時修改鏈接目標。在我輸出下一篇相關主題的文章前,感興趣的讀者不防率先品鑒我的另一個github工程request-window-attention尋找答案,和給我的工程點個star! 創(chuàng)作不易,值得(文章)點贊,(github工程)點star,和(兩者都)轉發(fā)。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    9603

    瀏覽量

    157673
  • API
    API
    +關注

    關注

    2

    文章

    2481

    瀏覽量

    67060
  • 編程
    +關注

    關注

    90

    文章

    3724

    瀏覽量

    97458
  • 應用程序
    +關注

    關注

    38

    文章

    3346

    瀏覽量

    60426

原文標題:堆對象生命周期管理

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    NAPI 類對象導出及其生命周期管理(下)

    NAPI 類對象導出及其生命周期管理(下)
    的頭像 發(fā)表于 05-16 10:25 ?4022次閱讀
    NAPI 類<b class='flag-5'>對象</b>導出及其<b class='flag-5'>生命周期</b><b class='flag-5'>管理</b>(下)

    鴻蒙開發(fā)接口公共事件與通知:【FFI能力】 N-API在Android、iOS平臺應用的使用指導

    N-API接口可以實現(xiàn)ArkTS/TS/JS與C/C++(Native)之間的交互,ArkUI-X中支持的N-API接口情況和使用場景請見[FFI能力(N-API)]。本文檔以[Ark
    的頭像 發(fā)表于 05-25 16:33 ?3581次閱讀
    鴻蒙開發(fā)接口公共事件與通知:【FFI能力】 <b class='flag-5'>N-API</b>在Android、iOS平臺應用的使用指導

    鴻蒙實戰(zhàn)開發(fā)-如何安全和高效的使用N-API開發(fā)Native模塊

    基礎能力的介紹,同時,方舟 ArkTS 運行時提供的 N-API 接口,封裝了方舟引擎的能力,在功能上與 Node.js 社區(qū)保持一致,這里不再贅述。 本文將結合應用開發(fā)場景,分別從對象生命周期
    發(fā)表于 05-09 15:55

    ServiceAbility的生命周期介紹

    ServiceAbility的生命周期 開發(fā)者可以根據(jù)業(yè)務場景重寫生命周期相關接口。ServiceAbility生命周期接口說明見下表。 表1 ServiceAbility生命周期
    發(fā)表于 05-28 08:22

    AutoScaling 生命周期掛鉤功能

    摘要: AutoScaling 伸縮組實例管理功能全面升級,新上線生命周期掛鉤(LifecycleHook)功能,方便用戶更加靈活地管理伸縮組內實例。使用生命周期掛鉤可以在伸縮組發(fā)生伸
    發(fā)表于 06-27 17:13

    理解數(shù)據(jù)生命周期管理思路

    數(shù)據(jù)生命周期管理的思考
    發(fā)表于 03-17 10:49

    HarmonyOS應用開發(fā)-PageAbility生命周期

    pageAbility的生命周期如下圖所示:在代碼中通過調用下列方法實現(xiàn)生命周期操作:onShow() :Ability由后臺不可見狀態(tài)切換到前臺可見狀態(tài)調用onShow方法,此時用戶在屏幕可以看到
    發(fā)表于 10-17 11:11

    觸覺智能RK3568使用體驗—NAPI 類對象導出及其生命周期管理(上)

    /n-api.html#n_api_environment_life_cycle_apis3. 關于本文提供的樣例工程本文提供了一個IDE開發(fā)的NAPI工程用來學習NAPI 類對象導出和對象生命周期
    發(fā)表于 02-08 17:10

    在S32G2 RM中有“生命周期”,生命周期的完整含義是什么?

    在S32G2 RM中,有“生命周期”。生命周期的完整含義是什么,我們應該如何使用它?
    發(fā)表于 04-23 10:37

    Synopsys 啟動硅生命周期管理計劃

    Synopsis 的數(shù)據(jù)分析驅動的硅生命周期管理計劃解決了 IC 生命周期中的質量、可靠性和安全挑戰(zhàn)。
    發(fā)表于 08-18 15:37 ?1526次閱讀
    Synopsys 啟動硅<b class='flag-5'>生命周期</b><b class='flag-5'>管理</b>計劃

    生命周期管理:COTS視角

    全面的生命周期管理策略是保護程序和緩解與長期任務關鍵型系統(tǒng)中部署的 COTS 技術相關的挑戰(zhàn)的關鍵。除了降低風險外,生命周期管理服務還通過確保及時購買和儲存報廢 (EOL) 組件并大大
    的頭像 發(fā)表于 11-08 14:18 ?2105次閱讀
    <b class='flag-5'>生命周期</b><b class='flag-5'>管理</b>:COTS視角

    觸覺智能RK3568使用體驗:NAPI 類對象導出及其生命周期管理(上)

    寫在開頭: OpenHarmony 中的 ?N-API組件定義了由ArkTS (JS/ETS)語言編寫的代碼和 native 代碼(使用 C/C++ 編寫)交互的方式,由 Node.js
    的頭像 發(fā)表于 02-17 09:10 ?2450次閱讀

    恭喜!華為云通過中國信通院《API生命周期管理能力評估》

    互聯(lián)互通。為助力企業(yè)高質量管理 API生命周期的發(fā)展目標,中國信通院牽頭制定了《API生命周期
    的頭像 發(fā)表于 10-26 09:16 ?1481次閱讀
    恭喜!華為云通過中國信通院《<b class='flag-5'>API</b> 全<b class='flag-5'>生命周期</b><b class='flag-5'>管理</b>能力評估》

    鴻蒙開發(fā)組件:DataAbility的生命周期

    應用開發(fā)者可以根據(jù)業(yè)務場景實現(xiàn)data.js/data.ets中的生命周期相關接口。DataAbility生命周期接口說明見下表。
    的頭像 發(fā)表于 06-20 09:39 ?1306次閱讀

    什么是PLM產(chǎn)品生命周期管理系統(tǒng)?

    在當今競爭激烈的制造業(yè)環(huán)境中,企業(yè)不僅要關注產(chǎn)品的設計和生產(chǎn),還需要對產(chǎn)品的整個生命周期進行全面管理。這包括了從產(chǎn)品概念構思、設計開發(fā)、生產(chǎn)制造、銷售分發(fā),到最終報廢處理的每一個環(huán)節(jié)。為了高效、系統(tǒng)
    的頭像 發(fā)表于 11-23 16:14 ?4698次閱讀
    什么是PLM產(chǎn)品<b class='flag-5'>生命周期</b><b class='flag-5'>管理</b>系統(tǒng)?
    清水河县| 贵溪市| 临猗县| 洮南市| 茌平县| 开阳县| 千阳县| 克什克腾旗| 民和| 施甸县| 蓬安县| 阿拉尔市| 多伦县| 平凉市| 崇州市| 台中县| 石狮市| 新竹县| 屏南县| 林周县| 大悟县| 衡东县| 孙吴县| 安康市| 鹿邑县| 青浦区| 鹤岗市| 固阳县| 瓮安县| 台东市| 滁州市| 石棉县| 泰兴市| 南澳县| 海安县| 海门市| 云阳县| 库尔勒市| 崇仁县| 工布江达县| 县级市|