FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 1: node::Abort() [/usr/local/bin/node] 2: node::OnFatalError(char const*, char const*) [/usr/local/bin/node] 3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/usr/local/bin/node] 4: v8::internal::Factory::NewFixedArray(int, v8::internal::PretenureFlag) [/usr/local/bin/node] 5: v8::internal::OrderedHashTable<v8::internal::OrderedHashMap, 2>::Rehash(v8::internal::Handle<v8::internal::OrderedHashMap>, int) [/usr/local/bin/node] 6: v8::internal::Runtime_MapGrow(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node] 7: 0x2ecd2d1042fd 8: 0x2ecd2d1b251e
由上述問題能夠確認,該node服務內存泄露. Node.js 進程的內存管理,都是有 V8 自動處理的,包括內存分配和釋放。那麼 V8 何時會將內存釋放呢?node
在 V8 內部,會爲程序中的全部變量構建一個圖,來表示變量間的關聯關係,當變量從根節點沒法觸達時,就意味着這個變量不會再被使用了,就是能夠回收的了。 而這個回收是一個過程性的,從快速 GC 到 最後的 Full GC,是須要一段時間的。 另外,Full GC 是有觸發閾值的,因此可能會出現內存長期佔用在一個高值,也能夠算是一種內存泄漏,能夠從《一次 Node.js 應用內存暴漲分析》中找到例子。還有一種就是引用不釋放,致使沒法進入 GC 環節,而且一直產生新的佔用,這通常會發生在 Javascript 層面。linux
因此,定位內存泄漏問題,通常方案就是找那些不被使用又不會被釋放的變量,處理了這些變量,問題通常就能夠解決了。若是是 Node.js 底層變量不釋放,除了提交 issue 等待解決外,只能經過優化啓動參數來解決。web
// node version > v0.8 npm install heapdump // Or, if you are running node.js v0.6 or v0.8: npm install heapdump@0.1.0
// express中,在app.js中加入 const heapdump = require('heapdump');
併發起少數幾回請求後,輸入以下命令,生成heap快照文件,記做name1chrome
kill -USR2 <pid>
因爲我這個是能夠提供給web調用的接口,所以用一個抓包工具charles(或者其餘模擬請求工具都行),重複發1000次請求,在用top命令查看該進程memery佔用狀況。發現問題能夠重現了。同時輸入以下命令:express
// in UNIX platforms kill -USR2 <pid> // 執行上述命令,會生成一下heap快照的文件,記做name2
6 、通過上述對比分析,能夠得知代碼存在的問題,而後做出相關優化。npm
好比,我這裏是用到了node-canvas 和 Echart,最後發現這兩個對象引用後一直沒有內內存回收,致使內存溢出。代碼層面作以下優化:canvas
stage.destroy(); chart.dispose(); chart = null; stage = null;
而後,啓動服務,模擬1000次請求,結果發現內存佔用比以前少了不少,基本上不會出現內存溢出的問題了。瀏覽器