首頁 web前端 js教程 Node.js 的記憶體限製到底是多少?

Node.js 的記憶體限製到底是多少?

Dec 25, 2024 am 04:35 AM

What Exactly Is the Memory Limit of Node.js?

熟練 Node.js API 可以讓您快速入門,但深入了解 Node.js 程式的記憶體佔用可以讓您走得更遠。

讓我們先透過 process.memoryUsage() 查看記憶體使用情況,每秒更新一次:

setInterval(() => { console.log('Memory Usage:', process.memoryUsage()); }, 1000);
登入後複製
登入後複製

由於輸出以位元組為單位,因此不方便使用者使用。讓我們透過將記憶體使用量格式化為 MB:
來修飾它

function formatMemoryUsageInMB(memUsage) {
    return {
        rss: convertToMB(memUsage.rss),
        heapTotal: convertToMB(memUsage.heapTotal),
        heapUsed: convertToMB(memUsage.heapUsed),
        external: convertToMB(memUsage.external)
    };
}

const convertToMB = value => {
    return (value / 1024 / 1024).toFixed(2) + ' MB';
};

const logInterval = setInterval(() => {
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}, 1000);
登入後複製
登入後複製

現在,我們每秒都可以得到以下輸出:

Memory Usage (MB): {
  rss: '30.96 MB', // The actual OS memory used by the entire program, including code, data, shared libraries, etc.
  heapTotal: '6.13 MB', // The memory area occupied by JS objects, arrays, etc., dynamically allocated by Node.js
                      // V8 divides the heap into young and old generations for different garbage collection strategies
  heapUsed: '5.17 MB',
  external: '0.39 MB'
}

Memory Usage (MB): {
  rss: '31.36 MB',
  heapTotal: '6.13 MB',
  heapUsed: '5.23 MB',
  external: '0.41 MB'
}
登入後複製

我們都知道V8引擎的記憶體使用是有限的,不僅受到作業系統的記憶體管理和資源分配策略的限制,還受到其自身的設定的限制。

使用 os.freemem(),我們可以看到作業系統有多少可用內存,但這並不意味著 Node.js 程式可以取得所有記憶體。

console.log('Free memory:', os.freemem());
登入後複製

對於 64 位元系統,Node.js V8 預設最大舊空間大小約為 1.4GB。這意味著即使您的作業系統有更多可用內存,V8 也不會自動使用超過此限制的內存。

提示:可以透過設定環境變數或啟動 Node.js 時指定參數來變更此限制。例如,如果您希望 V8 使用更大的堆,可以使用 --max-old-space-size 選項:

node --max-old-space-size=4096 your_script.js
登入後複製

這個數值需要根據你的實際狀況和場景來設定。比如說,如果你有一台大記憶體的機器,獨立部署,還有很多小記憶體的機器分散部署,這個值的設定一定會有所不同。

讓我們透過無限地向數組填充資料來運行測試,直到記憶體溢出,看看什麼時候會發生。

const array = [];
while (true) {
    for (let i = 0; i < 100000; i++) {
        array.push(i);
    }
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}
登入後複製

這是我們直接執行程式時得到的結果。新增一段資料後,程式崩潰了。

Memory Usage (MB): {
  rss: '2283.64 MB',
  heapTotal: '2279.48 MB',
  heapUsed: '2248.73 MB',
  external: '0.40 MB'
}
Memory Usage (MB): {
  rss: '2283.64 MB',
  heapTotal: '2279.48 MB',
  heapUsed: '2248.74 MB',
  external: '0.40 MB'
}


#
# Fatal error in , line 0
# Fatal JavaScript invalid size error 169220804
#
#
#
#FailureMessage Object: 0x7ff7b0ef8070
登入後複製

困惑嗎?不是限制1.4G嗎?為什麼要使用2G以上?實際上,Node.js 的 1.4GB 限制是 V8 引擎的歷史限制,適用於早期的 V8 版本和某些配置。在現代 Node.js 和 V8 中,Node.js 會根據系統資源自動調整其記憶體使用情況。在某些情況下,它可能使用遠超過 1.4GB 的空間,特別是在處理大型資料集或運行記憶體密集型操作時。

當我們將記憶體限制設為 512M 時,當 rss 達到 996 MB 左右時就會溢位。

Memory Usage (MB): {
  rss: '996.22 MB',
  heapTotal: '993.22 MB',
  heapUsed: '962.08 MB',
  external: '0.40 MB'
}
Memory Usage (MB): {
  rss: '996.23 MB',
  heapTotal: '993.22 MB',
  heapUsed: '962.09 MB',
  external: '0.40 MB'
}

<--- Last few GCs --->

[22540:0x7fd27684d000]     1680 ms: Mark-sweep 643.0 (674.4) -> 386.8 (419.4) MB, 172.2 / 0.0 ms  (average mu = 0.708, current mu = 0.668) allocation failure; scavenge might not succeed
[22540:0x7fd27684d000]     2448 ms: Mark-sweep 962.1 (993.2) -> 578.1 (610.7) MB, 240.7 / 0.0 ms  (average mu = 0.695, current mu = 0.687) allocation failure; scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
登入後複製

綜上所述,更準確的來說,Node.js 的記憶體限制是指堆記憶體限制,即 JS 物件、陣列等可以佔用的最大內存,由 V8 分配。

堆記憶體的大小決定了Node.js進程可以佔用多少記憶體嗎?不!繼續閱讀。

我可以將 3GB 檔案放入 Node.js 記憶體中嗎?

我們在測試中看到,在程式崩潰之前,陣列只能容納 2GB 多一點。那麼,如果我有一個 3GB 的文件,我不能把它一次放入 Node.js 記憶體嗎?

你可以的!

我們透過process.memoryUsage()看到了一個外部內存,它被Node.js進程佔用,但沒有被V8分配。只要你把3GB的檔案放在那裡,就沒有記憶體限制。如何?您可以使用緩衝區。 Buffer 是 Node.js 的 C 擴充模組,它使用 C 來分配內存,而不是 JS 物件和資料。

這是一個示範:

setInterval(() => { console.log('Memory Usage:', process.memoryUsage()); }, 1000);
登入後複製
登入後複製

即使你分配了3GB內存,我們的程式仍然可以順利運行,而我們的Node.js程式佔用了超過5GB內存,因為這個外部內存不是Node.js限制的,而是操作系統對分配內存的限製到線程(所以不能胡作非為,連Buffer 都會記憶體不足;本質是用Streams 來處理大數據)。

在 Node.js 中,Buffer 物件的生命週期與 JavaScript 物件相關聯。當 JavaScript 對 Buffer 物件的參考被刪除時,V8 垃圾收集器會將該物件標記為可回收,但 Buffer 物件的底層記憶體不會立即釋放。通常,當呼叫 C 擴展的析構函數時(例如 Node.js 中的垃圾回收過程),這部分記憶體會被釋放。然而,這個過程可能與V8的垃圾收集並不完全同步。

function formatMemoryUsageInMB(memUsage) {
    return {
        rss: convertToMB(memUsage.rss),
        heapTotal: convertToMB(memUsage.heapTotal),
        heapUsed: convertToMB(memUsage.heapUsed),
        external: convertToMB(memUsage.external)
    };
}

const convertToMB = value => {
    return (value / 1024 / 1024).toFixed(2) + ' MB';
};

const logInterval = setInterval(() => {
    const memoryUsageMB = formatMemoryUsageInMB(process.memoryUsage());
    console.log(`Memory Usage (MB):`, memoryUsageMB);
}, 1000);
登入後複製
登入後複製

總結:Node.js 記憶體使用量由 JS 堆記憶體使用量(由 V8 的垃圾回收決定)和 C 記憶體分配組成

為什麼堆記憶體分為新代和老代?

分代垃圾收集策略在現代程式語言的實作中非常普遍! Ruby、.NET 和 Java 中都可以找到類似分代垃圾收集的類似策略。當垃圾回收發生時,常常會導致「stop the world」的情況,這不可避免地影響程式效能。然而,這種設計是考慮到性能優化的。

  • 不同的物件壽命 在程式開發過程中,很大一部分變數是臨時的,用於完成特定的本地計算任務。這樣的變數更適合Minor GC,即新一代GC。新一代記憶體中的物件主要透過Scavenge演算法進行垃圾回收。 Scavenge 演算法將堆疊記憶體一分為二,即 From 和 To(經典的空間換時間權衡。由於它們的生存時間較短,因此不會消耗大量記憶體)。

記憶體分配時,發生在 From 內。在垃圾回收期間,會檢查 From 中的活動物件並將其複製到 To,然後釋放非活動物件。在下一輪收集中,To 中的活動物件將被複製到 From,此時 To 會轉變為 From,反之亦然。在每個垃圾收集週期中,From 和 To 都會交換。此演算法在複製過程中僅複製存活對象,從而避免記憶體碎片的產生。
那麼,變數的活躍度是如何決定的呢?可達性分析開始發揮作用。以以下物件為例:

  • globalObject:全域物件。
  • obj1:被globalObject直接引用的物件。
  • obj2:obj1所引用的物件。
  • obj3:一個孤立的對象,沒有任何其他對象的引用。

在可達性分析的背景下:

  • globalObject 作為根對象,本質上是可存取的。
  • obj1,由於被globalObject引用,也是可達的。
  • obj2 被 obj1 引用,因此也是可訪問的。
  • 相較之下,obj3 由於缺少根物件或其他可到達物件的任何引用路徑,因此被判定為不可到達,因此符合回收條件。

誠然,引用計數可以作為一種輔助手段。然而,在存在循環引用的情況下,它無法準確地確定物體的真實活性。

在老年代記憶體中,物件通常較不活躍。但當老年代記憶體滿了時,會透過Mark-Sweep演算法觸發老年代記憶體的清理(Major GC)。

標記-清除演算法包括兩個階段:標記和清除。在標記階段,V8 引擎會遍歷堆中的所有物件並標記存活的物件。在清掃階段,僅清除未標記的物件。此演算法的優點是,由於老年代中死亡對象的比例相對較小,因此清理階段消耗的時間相對較少。但它的缺點是只清除而不壓縮,可能會導致記憶體空間不連續,不方便為大物件分配記憶體。

這個缺點會導致記憶體碎片,需要使用另一種演算法,Mark-Compact。此演算法將所有存活物件移至一端,然後一舉消滅邊界右側的無效記憶體空間,從而獲得完整且連續的可用記憶體空間。它解決了 Mark-Sweep 演算法可能導致的記憶體碎片問題,但代價是移動大量活動物件會花費更多時間。

如果您覺得這篇文章有用,請按讚。 :D

以上是Node.js 的記憶體限製到底是多少?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1422
52
Laravel 教程
1316
25
PHP教程
1267
29
C# 教程
1239
24
神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的演變:當前的趨勢和未來前景 JavaScript的演變:當前的趨勢和未來前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

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

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

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

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

JavaScript:探索網絡語言的多功能性 JavaScript:探索網絡語言的多功能性 Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

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

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

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

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

從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等概念,增強了靈活性和異步編程能力。

See all articles