搜尋
首頁web前端js教程nodeJs記憶體洩漏問題詳解

之前一次偶然機會發現,react 在server渲染時,當NODE_ENV != production時,會導致記憶體洩漏。具體issues: https://github.com/facebook/react/issues/7406 。隨著node,react同構等技術地廣泛運用,node端記憶體洩漏等問題應該引起我們的重視。為什麼node容易出現記憶體洩漏以及出現之後應該如何排查,以下透過一個簡單的介紹以及例子來說明。

首先,node是基於v8引擎基礎上,其記憶體管理方式與v8一致。以下簡單介紹v8的相關記憶體特效。

V8記憶體限制

node基於V8構建,透過V8的方式進行分配跟管理js物件。 V8對記憶體的使用有限制(老生代記憶體64位元系統下約為1.4G,32位元系統下約為0.7G,新生代記憶體64位元系統下約32MB,32系統下約為16MB)。在這樣的限制下,將導致無法操作大內存物件。如果不小心觸碰這個界限,就會造成進程退出。

原因:V8執行垃圾回收時會阻塞JavaScript應用邏輯,直到垃圾回收結束再重新執行JavaScript應用邏輯,這種行為被稱為「全停頓」(stop-the-world)。若V8的堆內存為1.5GB,V8做一次小的垃圾回收需要50ms以上,做一次非增量式的垃圾回收甚至要1秒以上。

透過node --max-old-space-size=xxx(單位MB) , node --max-new-space-size=xxx(單位KB) 設定新生代記憶體以及老生代記憶體來破解預設的記憶體限制。

V8的堆構成

V8的堆其實並不只是由老生代和新生代兩部分構成,可以將堆分為幾個不同的區域:

新生代內存區:大多數的對像被分配在這裡,這個區域很小但是垃圾回特別頻繁

老生代指針區:屬於老生代,這裡包含了大多數可能存在指向其他對象的指針的對象,大多數從新生代晉升的對象會被移動到這裡

老生代資料區:屬於老生代,這裡只保存原始資料對象,這些對象沒有指向其他對象的指針

大對象區:這裡存放體積超越其他區大小的對象,每個對像有自己的內存,垃圾回收其不會移動大對象

代碼區:代碼對象,也就是包含JIT之後指令的對象,會被分配在這裡。唯一擁有執行權限的記憶體區

Cell區、屬性Cell區、Map區:存放Cell、屬性Cell和Map,每個區域都是存放相同大小的元素,結構簡單

GC回收類型

增量式GC

表示垃圾回收器在掃描記憶體空間時是否收集(增加)垃圾並在掃描週期結束時清空垃圾。

非增量式GC

使用非增量式垃圾收集器時,一收集到垃圾即將其清空。

垃圾回收器只會針對新生代記憶區、老生代指針區以及老生代資料區進行垃圾回收。物件首先進入佔用空間較少的新生代記憶體。大部分物件會很快失效,非增量GC直接回收這些少量記憶體。假如有些物件一段時間內不能被回收,則進去老生代內存區。這個區域則執行不頻繁的增量GC,且耗時較長。

那什麼時候才會導致記憶體洩漏的發生呢?

記憶體洩漏的途徑

記憶體洩漏

快取

隊列消費不及時

作用域未釋放

Node的記憶體構成主要是透過V8進行分配的部分和Node自行分配的部分。受V8的垃圾回收限制的主要是V8的堆內存。造成記憶體洩漏的主因:1,快取;2,佇列消費不及時;3,作用域未釋放

記憶體洩漏分析

查看V8記憶體使用量(單位byte)

process.memoryUsage();
  {
    ress: 47038464, 
    heapTotal: 34264656, 
    heapUsed: 2052866 
  }

   

進程的常駐記憶體部分

heapTotal,heapUsed:V8堆內存資訊

查看系統記憶體使用情況(單位byte)


os.totalmem()
os.freemem()

os.totalmem()

os.freemem()

os.totalmem()

os.freemem()


查看垃圾回收日誌

node --trace_gc -e "var a = []; for( var i = 0; i > gc.log  //輸出垃圾回收日誌


node --prof //輸出node執行時效能日誌。 使用windows-tick.processor查看。


分析監控工具

v8-profiler 對v8堆內存抓取快照和對cpu進行分析

node-heapdump 對v8堆內存抓取快照

node-mtrace 分析堆棧使用

nodede-memwatch

node-memwatch

memwatch.on('stats',function(info){
  console.log(info)
})
memwatch.on('leak',function(info){
  console.log(info)
})

   

stats事件:每次進行全堆垃圾回收時,將觸發一次stats事件。這個事件將會傳遞記憶體統計資訊。

{
"num_full_gc": 17, //第几次全栈垃圾回收
"num_inc_gc": 8,  //第几次增量垃圾回收
"heap_compactions": 8, //第几次对老生代进行整理
"estimated_base": 2592568, //预估基数
"current_base": 2592568, //当前基数
"min": 2499912, //最小
"max": 2592568, //最大
"usage_trend": 0 //使用趋势
  }

   

觀察num_full_gc和num_inc_gc反映垃圾回收。

leak事件:如果經過連續5次垃圾回收後,記憶體仍然沒有被釋放,意味著記憶體洩漏的發生。這時候會觸發一個leak事件。 🎜
{ start: Fri, 29 Jun 2012 14:12:13 GMT,
end: Fri, 29 Jun 2012 14:12:33 GMT,
growth: 67984,
reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr'
}
🎜   🎜🎜🎜

Heap Diffing 堆内存比较 排查内存溢出代码。
下面,我们通过一个例子来演示如何排查定位内存泄漏:

首先我们创建一个导致内存泄漏的例子:

//app.js
var app = require('express')();
var http = require('http').Server(app);
var heapdump = require('heapdump');
 
var leakobjs = [];
function LeakClass(){
  this.x = 1;
}
 
app.get('/', function(req, res){
  console.log('get /');
  for(var i = 0; i < 1000; i++){
    leakobjs.push(new LeakClass());
  }
  res.send(&#39;<h1 id="Hello-nbsp-world">Hello world</h1>&#39;);
});
 
setInterval(function(){
  heapdump.writeSnapshot(&#39;./&#39; + Date.now() + &#39;.heapsnapshot&#39;);
}, 3000);
 
http.listen(3000, function(){
  console.log(&#39;listening on port 3000&#39;);
});

   

这里我们通过设置一个不断增加且不回被回收的数组,来模拟内存泄漏。

通过使用heap-dump模块来定时纪录内存快照,并通过chrome开发者工具profiles来导入快照,对比分析。

我们可以看到,在浏览器访问 localhost:3000 ,并多次刷新后,快照的大小一直在增长,且即使不请求,也没有减小,说明已经发生了泄漏。

nodeJs記憶體洩漏問題詳解

接着我们通过过chrome开发者工具profiles, 导入快照。通过设置comparison,对比初始快照,发送请求,平稳,再发送请求这3个阶段的内存快照。可以发现右侧new中LeakClass一直增加。在delta中始终为正数,说明并没有被回收。

nodeJs記憶體洩漏問題詳解

小结

针对内存泄漏可以采用植入memwatch,或者定时上报process.memoryUsage内存使用率到monitor,并设置告警阀值进行监控。

当发现内存泄漏问题时,若允许情况下,可以在本地运行node-heapdump,使用定时生成内存快照。并把快照通过chrome Profiles分析泄漏原因。若无法本地调试,在测试服务器上使用v8-profiler输出内存快照比较分析json(需要代码侵入)。

需要考虑在什么情况下开启memwatch/heapdump。考虑heapdump的频度以免耗尽了CPU。 也可以考虑其他的方式来检测内存的增长,比如直接监控process.memoryUsage()。

当心误判,短暂的内存使用峰值表现得很像是内存泄漏。如果你的app突然要占用大量的CPU和内存,处理时间可能会跨越数个垃圾回收周期,那样的话memwatch很有可能将之误判为内存泄漏。但是,这种情况下,一旦你的app使用完这些资源,内存消耗就会降回正常的水平。所以需要注意的是持续报告的内存泄漏,而可以忽略一两次突发的警报。

更多nodeJs記憶體洩漏問題詳解相关文章请关注PHP中文网!


陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版