一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - node.js - Node.js ObjectWrap 的弱引用問題

Node.js ObjectWrap 的弱引用問題

2022-01-04 22:27編程雜技theanarkh node.js

最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。

Node.js ObjectWrap 的弱引用問題

前言:最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。

ObjectWrap 用于寫 Addon 的時候導出 C++ 對象給 JS 層使用,大致用法如下。首先定義一個 C++ 類。

  1. class Demo: public node::ObjectWrap { 
  2.      public
  3.          static void create(const FunctionCallbackInfo<Value>& args) { 
  4.                     new Demo(args.This()); 
  5.          } 
  6.          Demo(Local<Object> object): node::ObjectWrap() {} 
  7.      private: 
  8.         uv_timer_t timer; 
  9.  
  10. }; 

然后導出這個類到 JS。

  1. void Initialize( 
  2.   Local<Object> exports, 
  3.   Local<Value> module, 
  4.   Local<Context> context 
  5. ) { 
  6.   Isolate *isolate = context->GetIsolate(); 
  7.   Local<FunctionTemplate> demo = FunctionTemplate::New(isolate, Demo::create); 
  8.   char * str = "Demo"
  9.   Local<String> name = String::NewFromUtf8(isolate, str, NewStringType::kNormal, strlen(str)).ToLocalChecked(); 
  10.   demo->InstanceTemplate()->SetInternalFieldCount(1); 
  11.   exports->Set(context, name, demo->GetFunction(context).ToLocalChecked()).Check(); 
  12.  
  13.  
  14. NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize) 

然后在 JS 通過以下方式調用。

  1. const { Demo } = require('demo.node'); 
  2.  
  3. const demo = new Demo(); 

可以看到 C++ Demo 類中有一個 uv_timer_t 成員。主要用來定時去抓取 V8 堆快照,所以把它注冊到 Libuv 中。

  1. uv_timer_init(loop, &timer); 
  2.  
  3. uv_timer_start(&timer, timer_cb, 1000, 1000); 

然后使用的過程中我們發現,定時器隨機觸發了幾次后,就不觸發了。經過多種測試無果后,我不得不編譯一個 debug 版本的 Node.js 進行單步調試,然后就發現了有意思的事情。第一次進入 poll io 階段時,一切正常,1 秒后超時。

Node.js ObjectWrap 的弱引用問題

但是后面再次進入 poll io 階段時,詭異的事情發生了。

Node.js ObjectWrap 的弱引用問題

超時時間變成了一個很大的數字,正常來說,我設置的每隔一秒超時一次,這里應該是 1才對,為什么會出現一個詭異的數字呢。思考了一下,猜想是這塊內存被釋放了,然后里面保存了一些臟數據,接著我給 Demo 類加了個析構函數。

  1. ~Demo() { 
  2.   LOG("dead"); 
  3.  

然后發現,這個類對象居然被析構了。通過棧追蹤發現邏輯來自于 ObjectWrap 的 WeakCallback。

Node.js ObjectWrap 的弱引用問題

WeakCallback 的代碼如下。

  1. static void WeakCallback(const v8::WeakCallbackInfo<ObjectWrap>& data) { 
  2.    ObjectWrap* wrap = data.GetParameter(); 
  3.    wrap->handle_.Reset(); 
  4.    delete wrap; 
  5.  

delete wrap 就是 delete 了 Demo 對象。而這個 WeakCallback 的源頭來自 ObjectWrap 的 MakeWeak。

  1. inline void MakeWeak() { 
  2.     persistent().SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); 

這個 MakeWeak 又來源于 Wrap。

  1. inline void Wrap(v8::Local<v8::Object> handle) { 
  2.     // 關聯 C++ 對象和 Demo 對象 
  3.     handle->SetAlignedPointerInInternalField(0, this); 
  4.     persistent().Reset(v8::Isolate::GetCurrent(), handle); 
  5.     MakeWeak(); 
  6.  

Wrap 是創建 Demo 對象時調用的函數。用于關聯 JS 層對象和 C++ 對象,關系如下。

Node.js ObjectWrap 的弱引用問題

所以 JS 創建一個 Demo 對象的時候,就會指向一個 C++ 對象,然后 Demo 對象也有個持久句柄指向這個 C++ 對象。但是它默認情況下調用了 MakeWeak,也就是弱引用。而 JS 層在創建完 Demo 對象后就離開了作用域,因為 JS 模塊是被函數包裹起來的,執行完變量就被 gc了,除非通過 module.exports 或全局變量保持對 C++ 對象的引用。所以就導致了 C++ 對象最終被 Demo 對象以弱引用的方式引用著,等待 gc 的時候被回收。這里又引出了另一個問題,當我把抓取快照的代碼改成一些簡單的代碼時,并不容易觸發這個問題,原因在于它沒有觸發 gc。后來我嘗試在 JS 層分配一些內存,最終也成功觸發了這個問題,因為下面的代碼會導致 gc。而 gc 的時候就把 C++ 對象回收了。

  1. setInterval(() => { 
  2.     Buffer.from('x'.repeat('10')) 
  3.  
  4. },3000) 

這個問題的解決方式就是調用 ObjectWrap 的 Ref 函數消除弱引用(或者在 JS 層保持對這個對象的引用)。

  1. virtual void Ref() { 
  2.     persistent().ClearWeak(); 
  3.     refs_++; 

回過頭來看看 Node.js 中另一個類似功能的類 BaseObject。

  1. BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object) 
  2.     : persistent_handle_(env->isolate(), object), env_(env) { 
  3.   object->SetAlignedPointerInInternalField(BaseObject::kSlot, static_cast<void*>(this)); 
  4.  

它并沒有設置弱引用的邏輯。所以在 Node.js 的 C++ 模塊里,我們也看不到主動調用 Ref 的代碼。這或許是使用 ObjectWrap 時需要注意的問題。

總結:大致分析了 ObjectWrap 相關的這個問題,但是其實排查過程比描述的繁瑣和困難,主要是一開始沒有用 debug 版本的 Node.js 進行調試,把排查聚焦在打快照的地方了,因為那里涉及了多線程操作同一個 isolate,所以以為是 V8 API 使用方式的問題??偟膩碚f,如果碰到 Node.js 詭異的一些問題,不妨打個 debug 版本的 Node.js 進行調試,可能會更快地找到問題,從中也能學到很多東西。

原文鏈接:https://mp.weixin.qq.com/s/u3IS6DWrhYsgLJ_v4H8nLw

延伸 · 閱讀

精彩推薦
  • node.js在瀏覽器中,把 Vite 跑起來了!

    在瀏覽器中,把 Vite 跑起來了!

    大家好,我是 ssh,前幾天在推上沖浪的時候,看到 Francois Valdy 宣布他制作了 browser-vite[1],成功把 Vite 成功在瀏覽器中運行起來了。這引起了我的興趣,如...

    前端從進階到入院9282022-01-11
  • node.jsNode.js 中如何收集和解析命令行參數

    Node.js 中如何收集和解析命令行參數

    這篇文章主要介紹了Node.js 中如何收集和解析命令行參數,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    descire8802021-12-28
  • node.jsnodejs中使用worker_threads來創建新的線程的方法

    nodejs中使用worker_threads來創建新的線程的方法

    這篇文章主要介紹了nodejs中使用worker_threads來創建新的線程的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友...

    flydean程序那些事8982022-01-06
  • node.jsk8s node節點重新加入master集群的實現

    k8s node節點重新加入master集群的實現

    這篇文章主要介紹了k8s node節點重新加入master集群的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋...

    Scarborought13922022-01-22
  • node.js詳解node.js創建一個web服務器(Server)的詳細步驟

    詳解node.js創建一個web服務器(Server)的詳細步驟

    這篇文章主要介紹了詳解node.js創建一個web服務器(Server)的詳細步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    王佳斌8952021-12-31
  • node.jsNode.js ObjectWrap 的弱引用問題

    Node.js ObjectWrap 的弱引用問題

    最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 ObjectWrap 的使用問題。...

    編程雜技9852022-01-04
  • node.jslinux服務器快速卸載安裝node環境(簡單上手)

    linux服務器快速卸載安裝node環境(簡單上手)

    這篇文章主要介紹了linux服務器快速卸載安裝node環境(簡單上手),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    mose-x8462022-01-22
  • node.jsrequire加載器實現原理的深入理解

    require加載器實現原理的深入理解

    這篇文章主要給大家介紹了關于require加載器實現原理的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需...

    隱冬8462022-03-03
主站蜘蛛池模板: 日b在线 | 二区三区视频 | 免费成人在线观看视频 | 91私密保健女子养生spa | 天天狠天天透 | 成人免费草草视频 | xxx88视频在线观看 | 99久久精品国产片久人 | 欧美三级不卡视频 | 我要看逼 | 美女奶口隐私免费视频网站 | 丝袜性爱| 亚洲天堂视频在线免费观看 | 国产一久久香蕉国产线看观看 | 魔法满屋免费观看完整版中文 | 国产成人久久精品推最新 | 91探花在线观看 | 西野翔全部作品在线观看 | 免费观看视频在线播放 | 午夜宅男宅女看在线观看 | 欧美亚洲国产一区二区三区 | 国产精品久久国产精品99 | 国产二区视频在线观看 | 黑人粗又长| 99精品视频在线观看免费播放 | 荡女人人爱 | 北海市副市长黄江老公 | 欧美日韩国产在线一区 | 青青草国产免费国产是公开 | 久久黄色大片 | 国产精品亚洲片在线不卡 | 久久精品国产清白在天天线 | 91亚洲精品第一综合不卡播放 | 微福利92合集 | 亚洲免费在线视频 | 视频高清在线观看 | 香蕉视频在线观看网址 | 第一次不是你高清在线观看 | 日本在线视 | 校花被吃奶还摸下面 | 国色天香社区视频免费高清在线观看 |