激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

香港云服务器
服務(wù)器之家 - 編程語言 - JavaScript - node.js - Node.js ObjectWrap 的弱引用問題

Node.js ObjectWrap 的弱引用問題

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

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

Node.js ObjectWrap 的弱引用問題

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

ObjectWrap 用于寫 Addon 的時候?qū)С?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. }; 

然后導(dǎo)出這個類到 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 通過以下方式調(diào)用。

  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); 

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

Node.js ObjectWrap 的弱引用問題

但是后面再次進(jìn)入 poll io 階段時,詭異的事情發(fā)生了。

Node.js ObjectWrap 的弱引用問題

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

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

然后發(fā)現(xiàn),這個類對象居然被析構(gòu)了。通過棧追蹤發(fā)現(xiàn)邏輯來自于 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.     // 關(guān)聯(lián) C++ 對象和 Demo 對象 
  3.     handle->SetAlignedPointerInInternalField(0, this); 
  4.     persistent().Reset(v8::Isolate::GetCurrent(), handle); 
  5.     MakeWeak(); 
  6.  

Wrap 是創(chuàng)建 Demo 對象時調(diào)用的函數(shù)。用于關(guān)聯(lián) JS 層對象和 C++ 對象,關(guān)系如下。

Node.js ObjectWrap 的弱引用問題

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

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

這個問題的解決方式就是調(diào)用 ObjectWrap 的 Ref 函數(shù)消除弱引用(或者在 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.  

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

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

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

延伸 · 閱讀

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

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

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

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

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

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

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

    nodejs中使用worker_threads來創(chuàng)建新的線程的方法

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

    flydean程序那些事8982022-01-06
  • node.jsk8s node節(jié)點重新加入master集群的實現(xiàn)

    k8s node節(jié)點重新加入master集群的實現(xiàn)

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

    Scarborought13922022-01-22
  • node.js詳解node.js創(chuàng)建一個web服務(wù)器(Server)的詳細(xì)步驟

    詳解node.js創(chuàng)建一個web服務(wù)器(Server)的詳細(xì)步驟

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

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

    Node.js ObjectWrap 的弱引用問題

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

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

    linux服務(wù)器快速卸載安裝node環(huán)境(簡單上手)

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

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

    require加載器實現(xiàn)原理的深入理解

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

    隱冬8462022-03-03
1029
主站蜘蛛池模板: 91九色蝌蚪国产 | 亚洲精品久久久久www | 亚洲婷婷日日综合婷婷噜噜噜 | 欧美国产精品一区二区 | av在线播放电影 | www.guochanav.com| 久久精品首页 | 欧美性生活久久 | 成人在线观看免费 | 刘亦菲一区二区三区免费看 | 欧美精品一区二区久久久 | 中文字幕在线免费播放 | 99热1 | 国产激情视频在线 | 久久艹逼 | 亚洲一区在线视频 | 超91在线| 999插插插| 日本在线视频免费观看 | 精品一区二区三区日本 | 二区三区偷拍浴室洗澡视频 | 日韩精品免费看 | av在线免费播放网站 | jizzjizz中国少妇中文 | 欧美亚洲黄色片 | 成人做爰s片免费看网站 | 日本搞逼视频 | 久久精品久久精品国产大片 | 欧美一级淫片免费播放口 | 亚洲第五色综合网 | 黄色毛片a级| 成人毛片免费看 | 日本网站一区二区三区 | 欧美成年视频 | 免费黄色小视频网站 | 国产欧美日韩一区二区三区四区 | 国产91九色 | 黄色小视频免费在线观看 | 国产精品久久久久免费视频 | 国产精品久久久久久久久久久久久久久 | 激情在线视频 |