Node.js 作密集型運算,或者所操做的數組、對象自己較大時,容易出現內存溢出的問題,這是因爲 Node.js 的運行環境依賴 V8 引擎致使的。若是常常有較大數據量運算等操做,須要對 Node.js 運行環境限制有充分的瞭解。javascript
做者簡介:koala,專一完整的 Node.js 技術棧分享,從 JavaScript 到 Node.js,再到後端數據庫,祝您成爲優秀的高級 Node.js 工程師。【程序員成長指北】做者,Github 博客開源項目 github.com/koala-codin…java
下面是咱們在Node.js應用中常常遇到的兩類內存溢出問題:node
示例1:當咱們須要批量處理一些數據(如:更新用戶某項信息)時,咱們可能須要一個較大的for或while循環來完成全部的數據的更新,如:git
for (var i = 0; i < 10000000; i++) {
((i) => {
var site = {};
site.name = 'koala';
site.domain = '程序員成長指北';
// 這裏是一個保存或更新等操做
setTimeout(()=>{
console.log(i, site);
}, 0)
})(i)
}
複製代碼
示例2:對象須要頻繁的建立/銷燬,或操做對象自己較大,如:程序員
var sites = [];
for (var x=0;x<5000;x++){
var site=[];
for (var y=0;y<5000;y++){
site = [y, 'koala', '程序員成長指北'];
sites.push(site);
}
}
複製代碼
上面兩類操做都會出現相似如下錯誤:github
<--- Last few GCs --->
……
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6
複製代碼
咱們都知道,V8是 Google 在 Chrome 瀏覽器中使用的 JavaScript 引擎。而在瀏覽器環境中,運算通常不須要多大內存。 V8 對每一個進程分配的運行內存,在32位系統中約爲700MB,而在64位系統中約爲1.4GB。數據庫
Node.js 程序之因此會出內存溢出的狀況,能夠分爲三方面的緣由:後端
在示例1中,每次運算所需的內存量並不大,但因爲for循環,形成V8內存不能及時釋放。隨着程序運行時候的增長,內存佔用量會愈來愈大,並最終致使內存的溢出。數組
在示例2中,可能所建立對象自己並無超過內存限制。可是除對象自己外:建立對象、對象引用、Node.js程序自己等都須要內存空間,這樣就很容易致使內存的溢出。瀏覽器
在Node.js應用開發過程當中,瞭解V8內存分配和JavaScript語言限制是Node程序的基本素質。咱們應該在應用中權衡利弊,綜合考慮內存與程序的運行效率。如下幾點防止內存溢出的建議:
await將代碼執行順序變爲了同步。這樣可使 V8 得到內存回收的機會,有效解決過多事件堆積形成的內存溢出。 咱們可使用await方法處理:
async function dbFuc() {
for (let i = 0; i < 10000000; i++) {
var site = {};
site.name = 'koala';
site.domain = '程序員成長指北';
// 這裏是一個保存或更新等操做
await console.log(i, site);
}
}
dbFuc();
複製代碼
每次循環V8都會回收內存一次,所以內存不會再溢出。但這樣作必然會形成運行效率的下降,而應該在速度在安全之間平衡,控制好循環的安全次數。 說明:實際開發中,上面這種雖然解決了內存溢出,可是仍然會形成進程阻塞,能夠開啓一個進程/線程來解決阻塞問題(具體能夠看個人這篇文章《深刻理解Node.js 進程與線程(8000長文完全搞懂)》)
Node.js提供了一個程序運行參數--max-old-space-size
,能夠經過該參數指定V8所佔用的內存空間,這樣能夠在必定程度上避免程序內存的溢出。 如,咱們能夠在運行示例2程序時指定使用4G的內存: node --max-old-space-size=4096 app
Node.js程序所使用的內存分爲兩類:
(注: fs 和 stream 這兩個模塊我在 Node 進階系列文章中已經詳細介紹了, 這裏就不贅述)
在程序容許的狀況下,應該將數據保存在Buffer中,而不是轉換成字符串等JS對象,這樣能夠避免V8內存的過多佔用。(buffer能夠看一下這篇文章《Node進階-探究不在V8堆內存中存儲的Buffer對象》)
require時,exports和module.exports的區別你真的懂嗎