最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

nodeJs內(nèi)存泄漏問(wèn)題詳解

 更新時(shí)間:2016年09月05日 08:59:28   作者:jaychen  
由于內(nèi)存泄漏在Node.js中非常的常見,可能在瀏覽器中應(yīng)用javascript時(shí),對(duì)于其內(nèi)存泄漏不是特別敏感,但作為服務(wù)器語(yǔ)言運(yùn)行時(shí),你就不得不去考慮這些問(wèn)題。

之前一次偶然機(jī)會(huì)發(fā)現(xiàn),react 在server渲染時(shí),當(dāng)NODE_ENV != production時(shí),會(huì)導(dǎo)致內(nèi)存泄漏。具體issues: https://github.com/facebook/react/issues/7406 。隨著node,react同構(gòu)等技術(shù)地廣泛運(yùn)用,node端內(nèi)存泄漏等問(wèn)題應(yīng)該引起我們的重視。為什么node容易出現(xiàn)內(nèi)存泄漏以及出現(xiàn)之后應(yīng)該如何排查,下面通過(guò)一個(gè)簡(jiǎn)單的介紹以及例子來(lái)說(shuō)明。

首先,node是基于v8引擎基礎(chǔ)上,其內(nèi)存管理方式與v8一致。下面簡(jiǎn)單介紹v8的相關(guān)內(nèi)存特效。

V8內(nèi)存限制

node基于V8構(gòu)建,通過(guò)V8的方式進(jìn)行分配跟管理js對(duì)象。V8對(duì)內(nèi)存的使用有限制(老生代內(nèi)存64位系統(tǒng)下約為1.4G,32位系統(tǒng)下約為0.7G,新生代內(nèi)存64位系統(tǒng)下約為32MB,32系統(tǒng)下約為16MB)。在這樣的限制下,將導(dǎo)致無(wú)法操作大內(nèi)存對(duì)象。如果不小心觸碰這個(gè)界限,就會(huì)造成進(jìn)程退出。

原因:V8在執(zhí)行垃圾回收時(shí)會(huì)阻塞JavaScript應(yīng)用邏輯,直到垃圾回收結(jié)束再重新執(zhí)行JavaScript應(yīng)用邏輯,這種行為被稱為“全停頓”(stop-the-world)。若V8的堆內(nèi)存為1.5GB,V8做一次小的垃圾回收需要50ms以上,做一次非增量式的垃圾回收甚至要1秒以上。

通過(guò)node --max-old-space-size=xxx(單位MB) , node --max-new-space-size=xxx(單位KB) 設(shè)置新生代內(nèi)存以及老生代內(nèi)存來(lái)破解默認(rèn)的內(nèi)存限制。

V8的堆構(gòu)成

V8的堆其實(shí)并不只是由老生代和新生代兩部分構(gòu)成,可以將堆分為幾個(gè)不同的區(qū)域:

  1. 新生代內(nèi)存區(qū):大多數(shù)的對(duì)象被分配在這里,這個(gè)區(qū)域很小但是垃圾回特別頻繁
  2. 老生代指針區(qū):屬于老生代,這里包含了大多數(shù)可能存在指向其他對(duì)象的指針的對(duì)象,大多數(shù)從新生代晉升的對(duì)象會(huì)被移動(dòng)到這里
  3. 老生代數(shù)據(jù)區(qū):屬于老生代,這里只保存原始數(shù)據(jù)對(duì)象,這些對(duì)象沒(méi)有指向其他對(duì)象的指針
  4. 大對(duì)象區(qū):這里存放體積超越其他區(qū)大小的對(duì)象,每個(gè)對(duì)象有自己的內(nèi)存,垃圾回收其不會(huì)移動(dòng)大對(duì)象
  5. 代碼區(qū):代碼對(duì)象,也就是包含JIT之后指令的對(duì)象,會(huì)被分配在這里。唯一擁有執(zhí)行權(quán)限的內(nèi)存區(qū)
  6. Cell區(qū)、屬性Cell區(qū)、Map區(qū):存放Cell、屬性Cell和Map,每個(gè)區(qū)域都是存放相同大小的元素,結(jié)構(gòu)簡(jiǎn)單

GC回收類型

增量式GC

表示垃圾回收器在掃描內(nèi)存空間時(shí)是否收集(增加)垃圾并在掃描周期結(jié)束時(shí)清空垃圾。

非增量式GC

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

垃圾回收器只會(huì)針對(duì)新生代內(nèi)存區(qū)、老生代指針區(qū)以及老生代數(shù)據(jù)區(qū)進(jìn)行垃圾回收。對(duì)象首先進(jìn)入占用空間較少的新生代內(nèi)存。大部分對(duì)象會(huì)很快失效,非增量GC直接回收這些少量?jī)?nèi)存。假如有些對(duì)象一段時(shí)間內(nèi)不能被回收,則進(jìn)去老生代內(nèi)存區(qū)。這個(gè)區(qū)域則執(zhí)行不頻繁的增量GC,且耗時(shí)較長(zhǎng)。

那什么時(shí)候才會(huì)導(dǎo)致內(nèi)存泄漏的發(fā)生呢?

內(nèi)存泄漏的途徑

  1. 內(nèi)存泄露
  2. 緩存
  3. 隊(duì)列消費(fèi)不及時(shí)
  4. 作用域未釋放

Node的內(nèi)存構(gòu)成主要是通過(guò)V8進(jìn)行分配的部分和Node自行分配的部分。受V8的垃圾回收限制的主要是V8的堆內(nèi)存。造成內(nèi)存泄漏的主要原因:1,緩存;2,隊(duì)列消費(fèi)不及時(shí);3,作用域未釋放

內(nèi)存泄漏分析

查看V8內(nèi)存使用情況(單位byte)

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

ress:進(jìn)程的常駐內(nèi)存部分

heapTotal,heapUsed:V8堆內(nèi)存信息

查看系統(tǒng)內(nèi)存使用情況(單位byte)

os.totalmem()
os.freemem()

返回系統(tǒng)總內(nèi)存以及閑置內(nèi)存

查看垃圾回收日志

node --trace_gc -e "var a = []; for( var i = 0; i < 1000000; i++ ) { a.push(new Array(100)); }" >> gc.log  //輸出垃圾回收日志

node --prof //輸出node執(zhí)行時(shí)性能日志。 使用windows-tick.processor查看。

分析監(jiān)控工具

v8-profiler 對(duì)v8堆內(nèi)存抓取快照和對(duì)cpu進(jìn)行分析
node-heapdump 對(duì)v8堆內(nèi)存抓取快照
node-mtrace 分析堆棧使用
node-memwatch 監(jiān)聽垃圾回收情況

node-memwatch

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

stats事件:每次進(jìn)行全堆垃圾回收時(shí),將觸發(fā)一次stats事件。這個(gè)事件將會(huì)傳遞內(nèi)存統(tǒng)計(jì)信息。

{
"num_full_gc": 17, //第幾次全棧垃圾回收
"num_inc_gc": 8,  //第幾次增量垃圾回收
"heap_compactions": 8, //第幾次對(duì)老生代進(jìn)行整理
"estimated_base": 2592568, //預(yù)估基數(shù)
"current_base": 2592568, //當(dāng)前基數(shù)
"min": 2499912, //最小
"max": 2592568, //最大 
"usage_trend": 0 //使用趨勢(shì)
  }

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

leak事件:如果經(jīng)過(guò)連續(xù)5次垃圾回收后,內(nèi)存仍然沒(méi)有被釋放,意味著內(nèi)存泄漏的發(fā)生。這個(gè)時(shí)候會(huì)觸發(fā)一個(gè)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 堆內(nèi)存比較 排查內(nèi)存溢出代碼。
下面,我們通過(guò)一個(gè)例子來(lái)演示如何排查定位內(nèi)存泄漏:

首先我們創(chuàng)建一個(gè)導(dǎo)致內(nèi)存泄漏的例子:

//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('<h1>Hello world</h1>');
});

setInterval(function(){
  heapdump.writeSnapshot('./' + Date.now() + '.heapsnapshot');
}, 3000);

http.listen(3000, function(){
  console.log('listening on port 3000');
});

這里我們通過(guò)設(shè)置一個(gè)不斷增加且不回被回收的數(shù)組,來(lái)模擬內(nèi)存泄漏。

通過(guò)使用heap-dump模塊來(lái)定時(shí)紀(jì)錄內(nèi)存快照,并通過(guò)chrome開發(fā)者工具profiles來(lái)導(dǎo)入快照,對(duì)比分析。

我們可以看到,在瀏覽器訪問(wèn) localhost:3000 ,并多次刷新后,快照的大小一直在增長(zhǎng),且即使不請(qǐng)求,也沒(méi)有減小,說(shuō)明已經(jīng)發(fā)生了泄漏。

接著我們通過(guò)過(guò)chrome開發(fā)者工具profiles, 導(dǎo)入快照。通過(guò)設(shè)置comparison,對(duì)比初始快照,發(fā)送請(qǐng)求,平穩(wěn),再發(fā)送請(qǐng)求這3個(gè)階段的內(nèi)存快照??梢园l(fā)現(xiàn)右側(cè)new中LeakClass一直增加。在delta中始終為正數(shù),說(shuō)明并沒(méi)有被回收。

小結(jié)

針對(duì)內(nèi)存泄漏可以采用植入memwatch,或者定時(shí)上報(bào)process.memoryUsage內(nèi)存使用率到monitor,并設(shè)置告警閥值進(jìn)行監(jiān)控。

當(dāng)發(fā)現(xiàn)內(nèi)存泄漏問(wèn)題時(shí),若允許情況下,可以在本地運(yùn)行node-heapdump,使用定時(shí)生成內(nèi)存快照。并把快照通過(guò)chrome Profiles分析泄漏原因。若無(wú)法本地調(diào)試,在測(cè)試服務(wù)器上使用v8-profiler輸出內(nèi)存快照比較分析json(需要代碼侵入)。

需要考慮在什么情況下開啟memwatch/heapdump。考慮heapdump的頻度以免耗盡了CPU。 也可以考慮其他的方式來(lái)檢測(cè)內(nèi)存的增長(zhǎng),比如直接監(jiān)控process.memoryUsage()。

當(dāng)心誤判,短暫的內(nèi)存使用峰值表現(xiàn)得很像是內(nèi)存泄漏。如果你的app突然要占用大量的CPU和內(nèi)存,處理時(shí)間可能會(huì)跨越數(shù)個(gè)垃圾回收周期,那樣的話memwatch很有可能將之誤判為內(nèi)存泄漏。但是,這種情況下,一旦你的app使用完這些資源,內(nèi)存消耗就會(huì)降回正常的水平。所以需要注意的是持續(xù)報(bào)告的內(nèi)存泄漏,而可以忽略一兩次突發(fā)的警報(bào)。

相關(guān)文章

  • node.js中的url.parse方法使用舉例

    node.js中的url.parse方法使用舉例

    url.parse()可以將一個(gè)完整的URL地址,分為很多部分,下面這篇文章主要給大家介紹了關(guān)于node.js中url.parse方法使用的相關(guān)資料,文中通過(guò)實(shí)例代碼和圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-03-03
  • 淺談node.js中間件有哪些類型

    淺談node.js中間件有哪些類型

    這篇文章主要介紹了node.js中間件有哪些類型,對(duì)中間件感興趣的同學(xué),可以參考下
    2021-04-04
  • nodeJS?express路由學(xué)習(xí)req.body與req.query方法實(shí)例詳解

    nodeJS?express路由學(xué)習(xí)req.body與req.query方法實(shí)例詳解

    這篇文章主要為大家介紹了nodeJS?express路由學(xué)習(xí)req.body與req.query方法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • node.js(express)中使用Jcrop進(jìn)行圖片剪切上傳功能

    node.js(express)中使用Jcrop進(jìn)行圖片剪切上傳功能

    最近在項(xiàng)目開發(fā)中遇到了這樣的需求就是要實(shí)現(xiàn)用戶上傳頭像,并且要保存用戶裁切后的部分作為用戶頭像。下面給大家分享node.js(express)中使用Jcrop進(jìn)行圖片剪切上傳功能,需要的的朋友參考下吧
    2017-04-04
  • nodejs如何將高版本降為低版本

    nodejs如何將高版本降為低版本

    在遇到項(xiàng)目依賴低版本Node.js時(shí),直接安裝低版本可能會(huì)遇到困難,本文提供了一種通過(guò)卸載當(dāng)前高版本Node.js并使用NVM(Node Version Manager)來(lái)管理和安裝低版本Node.js的方法,首先,需要卸載現(xiàn)有的Node.js環(huán)境并清理相關(guān)文件
    2024-10-10
  • Node.js靜態(tài)服務(wù)器的實(shí)現(xiàn)方法

    Node.js靜態(tài)服務(wù)器的實(shí)現(xiàn)方法

    這篇文章主要介紹了Node.js靜態(tài)服務(wù)器的實(shí)現(xiàn)方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • node.js中的require使用詳解

    node.js中的require使用詳解

    本文通過(guò)幾個(gè)具體實(shí)例來(lái)分析講解了node.js中require的使用方法,非常的詳盡,這里推薦給大家
    2014-12-12
  • node中IO以及定時(shí)器優(yōu)先級(jí)詳解

    node中IO以及定時(shí)器優(yōu)先級(jí)詳解

    這篇文章主要給大家介紹了關(guān)于node中IO以及定時(shí)器優(yōu)先級(jí)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用node具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程記錄

    webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程記錄

    webpack在前端工程領(lǐng)域起到了中流砥柱的作用,理解它的內(nèi)部實(shí)現(xiàn)機(jī)制會(huì)對(duì)你的工程建設(shè)提供很大的幫助(不論是定制功能還是優(yōu)化打包),下面這篇文章主要給大家介紹了關(guān)于webpack創(chuàng)建項(xiàng)目并打包的詳細(xì)流程,需要的朋友可以參考下
    2023-03-03
  • nodeJs鏈接Mysql做增刪改查的簡(jiǎn)單操作

    nodeJs鏈接Mysql做增刪改查的簡(jiǎn)單操作

    本篇文章主要介紹了nodeJs鏈接Mysql做增刪改查的簡(jiǎn)單操作,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02

最新評(píng)論

右玉县| 江口县| 施甸县| 伊吾县| 邢台市| 湄潭县| 浏阳市| 砀山县| 乌鲁木齐县| 荔浦县| 北安市| 保亭| 长岛县| 交口县| 鄄城县| 太原市| 通山县| 韩城市| 天台县| 达州市| 托克托县| 新宁县| 昆明市| 朝阳县| 兴国县| 米林县| 抚顺市| 汶上县| 潜山县| 淮安市| 浦东新区| 汶上县| 嘉兴市| 昌图县| 乌兰察布市| 赣州市| 来凤县| 新泰市| 佳木斯市| 湖北省| 永顺县|