溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

nodejs如何檢查內(nèi)存泄漏

發(fā)布時(shí)間:2021-11-23 15:36:01 來(lái)源:億速云 閱讀:506 作者:iii 欄目:web開(kāi)發(fā)

本篇內(nèi)容介紹了“nodejs如何檢查內(nèi)存泄漏”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

node中可利用memwatch工具來(lái)檢查內(nèi)存泄漏,方法:1、使用npm進(jìn)行工具的安裝;2、在項(xiàng)目中添加“var memwatch=require('memwatch');memwatch.setup();”代碼;3、監(jiān)聽(tīng)leak事件即可。

nodejs如何檢查內(nèi)存泄漏

本教程操作環(huán)境:windows7系統(tǒng)、nodejs 12.19.0版,DELL G3電腦。

追蹤Node.js代碼中的內(nèi)存泄漏一直是一個(gè)很有挑戰(zhàn)的難題。本文討論如何從一個(gè)node寫(xiě)的應(yīng)用里自動(dòng)的跟蹤到內(nèi)存泄漏問(wèn)題,在這里筆者向大家推薦兩款追查內(nèi)存問(wèn)題的神器 —— memwatch 和 heapdump

首先,我們來(lái)看一個(gè)簡(jiǎn)單的內(nèi)存泄漏

var http = require('http');
 
var server = http.createServer(function (req, res) {
 for (var i=0; i<1000; i++) {
   server.on('request', function leakyfunc() {});
 }
 
 res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
server.setMaxListeners(0);
console.log('Server running at http://127.0.0.1:1337/. Process PID: ', process.pid);

每一個(gè)請(qǐng)求我們?cè)黾恿?000個(gè)導(dǎo)致泄漏的監(jiān)聽(tīng)器。如果我們?cè)谝粋€(gè)shell控制臺(tái)中執(zhí)行以下命令:

while true; do curl http://127.0.0.1:1337/; done

然后在另外一個(gè)shell控制臺(tái)中查看我們的進(jìn)程

top -pid

我們會(huì)看到node進(jìn)程產(chǎn)生異常高的內(nèi)存占用,我們的node進(jìn)程看起來(lái)失控了。那么,當(dāng)我們的node進(jìn)程出現(xiàn)這種情況的時(shí)候,通常我們?cè)撛鯓釉\斷出問(wèn)題的根源?

內(nèi)存泄露的檢測(cè)

npm模塊 memwatch 是一個(gè)非常好的內(nèi)存泄漏檢查工具,讓我們先將這個(gè)模塊安裝到我們的app中去,執(zhí)行以下命令:

npm install --save memwatch

然后,在我們的代碼中,添加:

var memwatch = require('memwatch');
memwatch.setup();

然后監(jiān)聽(tīng) leak 事件

memwatch.on('leak', function(info) {
 console.error('Memory leak detected: ', info);
});;

這樣當(dāng)我們執(zhí)行我們的測(cè)試代碼,我們會(huì)看到下面的信息:

{
 start: Fri Jan 02 2015 10:38:49 GMT+0000 (GMT),
 end: Fri Jan 02 2015 10:38:50 GMT+0000 (GMT),
 growth: 7620560,
 reason: 'heap growth over 5 consecutive GCs (1s) - -2147483648 bytes/hr'
}

memwatch發(fā)現(xiàn)了內(nèi)存泄漏!memwatch 判定內(nèi)存泄漏事件發(fā)生的規(guī)則如下:

當(dāng)你的堆內(nèi)存在5個(gè)連續(xù)的垃圾回收周期內(nèi)保持持續(xù)增長(zhǎng),那么一個(gè)內(nèi)存泄漏事件被派發(fā)

了解更加詳細(xì)的內(nèi)容,查看 memwatch

內(nèi)存泄漏分析

使用memwatch我們發(fā)現(xiàn)了存在內(nèi)存泄漏,這非常好,但是現(xiàn)在呢?我們還需要定位內(nèi)存泄漏出現(xiàn)的實(shí)際位置。要做到這一點(diǎn),有兩種方法可以使用。

memwatch heap diff

通過(guò)memwatch你可以得到堆內(nèi)存使用量和內(nèi)存隨程序運(yùn)行產(chǎn)生的差異。詳細(xì)的文檔在這里

例如,我們可以在兩個(gè)leak事件發(fā)生的間隔中做一個(gè)heap dump

var hd;
memwatch.on('leak', function(info) {
 console.error(info);
 if (!hd) {
   hd = new memwatch.HeapDiff();
 } else {
   var diff = hd.end();
   console.error(util.inspect(diff, true, null));
   hd = null;
 }
});

執(zhí)行這段代碼會(huì)輸出更多的信息:

{ before: {
   nodes: 244023,
   time: Fri Jan 02 2015 12:13:11 GMT+0000 (GMT),
   size_bytes: 22095800,
   size: '21.07 mb' },
 after: {
   nodes: 280028,
   time: Fri Jan 02 2015 12:13:13 GMT+0000 (GMT),
   size_bytes: 24689216,
   size: '23.55 mb' },
 change: {
   size_bytes: 2593416,
   size: '2.47 mb',
   freed_nodes: 388,
   allocated_nodes: 36393,
   details:
   [ { size_bytes: 0,
   '+': 0,
   what: '(Relocatable)',
   '-': 1,
   size: '0 bytes' },
   { size_bytes: 0,
   '+': 1,
   what: 'Arguments',
   '-': 1,
   size: '0 bytes' },
   { size_bytes: 2856,
   '+': 223,
   what: 'Array',
   '-': 201,
   size: '2.79 kb' },
   { size_bytes: 2590272,
   '+': 35987,
   what: 'Closure',
   '-': 11,
   size: '2.47 mb' },
...

所以在內(nèi)存泄漏事件之間,我們發(fā)現(xiàn)堆內(nèi)存增長(zhǎng)了2.47MB,而導(dǎo)致內(nèi)存增長(zhǎng)的罪魁禍?zhǔn)资?strong>閉包。如果你的泄漏是由某個(gè)class造成的,那么what字段可能會(huì)輸出具體的class名字,所以這樣的話(huà),你會(huì)獲得足夠的信息來(lái)幫助你最終定位到泄漏之處。

然而,在我們的例子中,我們唯一獲得的信息只是泄漏來(lái)自于閉包,這個(gè)信息非常有用,但是仍不足以在一個(gè)復(fù)雜的應(yīng)用中迅速找到問(wèn)題的來(lái)源(復(fù)雜的應(yīng)用往往有很多的閉包,不知道哪一個(gè)造成了內(nèi)存泄漏——譯者注)

所以我們?cè)撛趺崔k呢?這時(shí)候該Heapdump出場(chǎng)了。

Heapdump

npm模塊node-heapdump是一個(gè)非凡的模塊,它可以使用來(lái)將v8引擎的堆內(nèi)存內(nèi)容dump出來(lái),這樣你就可以在Chrome的開(kāi)發(fā)者工具中查看問(wèn)題。你可以在開(kāi)發(fā)工具中對(duì)比不同運(yùn)行階段的堆內(nèi)存快照,這樣可以幫助你定位到內(nèi)存泄漏的位置。要想了解heapdump的更多內(nèi)容,可以閱讀這篇文章

現(xiàn)在讓我們來(lái)試試 heapdump,在每一次發(fā)現(xiàn)內(nèi)存泄漏的時(shí)候,我們都將此時(shí)的內(nèi)存堆??煺諏?xiě)入磁盤(pán)中:

memwatch.on('leak', function(info) {
 console.error(info);
 var file = '/tmp/myapp-' + process.pid + '-' + Date.now() + '.heapsnapshot';
 heapdump.writeSnapshot(file, function(err){
   if (err) console.error(err);
   else console.error('Wrote snapshot: ' + file);
  });
});

運(yùn)行我們的代碼,磁盤(pán)上會(huì)產(chǎn)生一些.heapsnapshot的文件到/tmp目錄下?,F(xiàn)在,在Chrome瀏覽器中,啟動(dòng)開(kāi)發(fā)者工具(在mac下的快捷鍵是alt+cmd+i),點(diǎn)擊Profiles標(biāo)簽并點(diǎn)擊Load按鈕載入我們的快照。

我們能夠很清晰地發(fā)現(xiàn)原來(lái)leakyfunc()是內(nèi)存泄漏的元兇。

我們依然還可以通過(guò)對(duì)比兩次記錄中heapdump的不同來(lái)更加迅速確認(rèn)兩次dump之間的內(nèi)存泄漏:

想要進(jìn)一步了解開(kāi)發(fā)者工具的memory profiling功能,可以閱讀 Taming The Unicorn: Easing JavaScript Memory Profiling In Chrome DevTools 這篇文章。

Turbo Test Runner

我們給Turbo - FeedHenry開(kāi)發(fā)的測(cè)試工具提交了一個(gè)小補(bǔ)丁 — 使用了上面所說(shuō)的內(nèi)存泄漏檢查技術(shù)。這樣就可以讓開(kāi)發(fā)者寫(xiě)針對(duì)內(nèi)存的單元測(cè)試了,如果模塊有內(nèi)存問(wèn)題,那么測(cè)試結(jié)果中就會(huì)產(chǎn)生相應(yīng)的警告。詳細(xì)了解具體的內(nèi)容,可以訪問(wèn)Turbo模塊。

“nodejs如何檢查內(nèi)存泄漏”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI