成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Node.js ObjectWrap 的弱引用問題

開發 前端
最近在寫 Node.js Addon 的過程中,遇到了一個問題,然后發現是 ObjectWrap 弱引用導致的,本文介紹一下具體的問題和排查過程,以及 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 秒后超時。

 

 

 

 

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

 

 

 

 

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

 

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

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

 

 

 

 

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++ 對象,關系如下。

 

 

 

 

所以 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 使用方式的問題。總的來說,如果碰到 Node.js 詭異的一些問題,不妨打個 debug 版本的 Node.js 進行調試,可能會更快地找到問題,從中也能學到很多東西。

 

責任編輯:姜華 來源: 編程雜技
相關推薦

2017-04-10 13:28:32

Node.jsJavaScript

2022-06-23 06:34:56

Node.js子線程

2023-06-30 23:25:46

HTTP模塊內存

2025-01-08 08:47:44

Node.js內存泄露定時器

2013-11-01 09:34:56

Node.js技術

2015-03-10 10:59:18

Node.js開發指南基礎介紹

2020-05-29 15:33:28

Node.js框架JavaScript

2012-02-03 09:25:39

Node.js

2021-12-25 22:29:57

Node.js 微任務處理事件循環

2011-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js

2011-09-02 14:47:48

Node

2011-09-09 14:23:13

Node.js

2011-11-10 08:55:00

Node.js

2012-10-24 14:56:30

IBMdw

2021-09-26 05:06:04

Node.js模塊機制

2021-11-06 18:40:27

js底層模塊

2011-11-02 09:04:15

Node.js

2019-07-09 14:50:15

Node.js前端工具

2015-06-23 15:27:53

HproseNode.js
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品夜色一区二区三区 | 一级毛片高清 | 天天色图 | 在线视频日韩 | 美女露尿口视频 | 日韩欧美中文字幕在线观看 | 一区二区三区视频在线观看 | 日韩在线不卡 | 欧美成人猛片aaaaaaa | 亚洲欧美日韩国产综合 | 九九热在线观看 | 中文字幕日韩一区 | 古典武侠第一页久久777 | 国产亚洲精品综合一区 | .国产精品成人自产拍在线观看6 | 香蕉一区二区 | 国产乱码精品一区二区三区五月婷 | 日韩高清一区二区 | 综合国产第二页 | 成人免费黄色 | 日本一区二区三区四区 | 欧洲一区在线观看 | 国产精品一区二区三区在线 | aaa国产大片| 亚洲精品1 | 欧美一级做a爰片免费视频 国产美女特级嫩嫩嫩bbb片 | 精品一区在线免费观看 | 四虎影院在线观看av | 久久久成人精品 | 亚洲视频在线看 | 99久久久久久久久 | 久久中文字幕av | 亚洲精品www. | 99re国产| 免费国产一区 | 亚洲高清视频在线观看 | 国产精品久久久久久久久久了 | 成年人在线观看视频 | 久久福利网站 | 日本精品一区二区三区视频 | 成人激情视频 |