nodejs v8 內存溢出問題


 

nodejs:

https://nodejs.org/dist/latest-v14.x/docs/api/cli.html#cli_max_old_space_size_size_in_megabytes

Useful V8 options#

V8 has its own set of CLI options. Any V8 CLI option that is provided to node will be passed on to V8 to handle. V8's options have no stability guarantee. The V8 team themselves don't consider them to be part of their formal API, and reserve the right to change them at any time. Likewise, they are not covered by the Node.js stability guarantees. Many of the V8 options are of interest only to V8 developers. Despite this, there is a small set of V8 options that are widely applicable to Node.js, and they are documented here:

--max-old-space-size=SIZE (in megabytes)#

Sets the max memory size of V8's old memory section. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory.

On a machine with 2GB of memory, consider setting this to 1536 (1.5GB) to leave some memory for other uses and avoid swapping.

$ node --max-old-space-size=1536 index.js

舊空間"是V8托管(也稱為垃圾收集)堆的最大且最可配置的部分(即JavaScript對象所在的位置),並且--max-old-space-size標志控制其最大大小.隨着內存消耗接近極限,V8將花費更多時間進行垃圾收集,以釋放未使用的內存.

如果堆內存消耗(即GC無法釋放的活動對象)超出限制,V8將使您的進程崩潰(缺少替代方案),因此您不希望將其設置得太低.當然,如果你設置得太高,那么V8允許的額外堆使用可能會導致整個系統內存不足(並且交換或殺死隨機進程,因為缺少備選方案).

Node對內存泄露十分敏感,一旦線上應用有成千上萬的流量,那怕是一個字節的內存泄漏也會造成堆積,垃圾回收過程中將會耗費更多時間進行對象掃描,應用響應緩慢,直到進程內存溢出,應用奔潰。

 

內存的限制

Node中並不像其他后端語言中,對內存的使用沒有多少限制。在Node中使用內存,只能使用到系統的一部分內存,64位系統下約為1.4GB,32位系統下約為0.7GB。這歸咎於Node使用了本來運行在瀏覽器的V8引擎。

V8引擎的設計之初只是運行在瀏覽器中,而在瀏覽器的一般應用場景下使用起來綽綽有余,足以勝任前端頁面中的所有需求。

雖然服務端操作大內存也不是常見的需求,但是萬一有這樣的需求,還是可以解除限制的。
在啟動node程序的時候,可以傳遞兩個參數來調整內存限制的大小。

node --max-nex-space-size=1024 app.js // 單位為KB node --max-old-space-size=2000 app.js // 單位為MB 

這兩條命令分別對應Node內存堆中的「新生代」和「老生代」



鏈接:https://www.jianshu.com/p/74a466789ff4

 

Node.js的8.0版本以上可以這樣調整

export NODE_OPTIONS=--max_old_space_size=4096 

也可以使用自動化、工程化配置插件

increase-memory-limit

https://gist.github.com/tjunghans/90ff3bbf575b8b1da41f3fb56e374931

Command line

node --help --v8-options | grep -B 1 -A 1 max-old-space
        type: bool  default: false
  --max-old-space-size (max size of the old space (in Mbytes))
        type: size_t  default: 0

"Old space" is the biggest and most configurable section of V8's managed (aka garbage-collected) heap (i.e. where the JavaScript objects live), and the --max-old-space-size flag controls its maximum size. As memory consumption approaches the limit, V8 will spend more time on garbage collection in an effort to free unused memory. If heap memory consumption (i.e. live objects that the GC cannot free) exceeds the limit, V8 will crash your process (for lack of alternative), so you don't want to set it too low. Of course, if you set it too high, then the additional heap usage that V8 will allow might cause your overall system to run out of memory (and either swap or kill random processes, for lack of alternative). In summary, on a machine with 2GB of memory I would probably set --max-old-space-size to about 1.5GB to leave some memory for other uses and avoid swapping.

Setting

export NODE_OPTIONS=--max-old-space-size=8192

References


nodejs內存使用:https://devcenter.heroku.com/articles/node-memory-use


https://grizzlybit.info/blog/increase-nodejs-memory-limit

In Node.js, we don't explicitly manage the memory, we rather leave it to v8 garbage collector to do that for us. But it might not have the wiggle room to crunch the data we want it to. Hence, we might end up with a FATAL ERROR like below:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: 0x1011d1c65 node::Abort() (.cold.1) [/usr/local/bin/node] 2: 0x10009f919 node::Abort() [/usr/local/bin/node] 3: 0x10009fa7f node::OnFatalError(char const*, char const*) [/usr/local/bin/node] 4: 0x1001e3867 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node] 5: 0x1001e3807 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node] 6: 0x10036b995 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/usr/local/bin/node] 7: 0x100373a3c v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node] 8: 0x10033fdbd v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::RootIndex, int, v8::internal::Object, v8::internal::AllocationType) [/usr/local/bin/node] 9: 0x1004b9d29 v8::internal::(anonymous namespace)::ElementsAccessorBase<v8::internal::(anonymous namespace)::FastHoleySmiElementsAccessor, v8::internal::(anonymous namespace)::ElementsKindTraits<(v8::internal::ElementsKind)1> >::GrowCapacityAndConvertImpl(v8::internal::Handle<v8::internal::JSObject>, unsigned int) [/usr/local/bin/node] 10: 0x1004b98e8 v8::internal::(anonymous namespace)::ElementsAccessorBase<v8::internal::(anonymous namespace)::FastHoleySmiElementsAccessor, v8::internal::(anonymous namespace)::ElementsKindTraits<(v8::internal::ElementsKind)1> >::SetLengthImpl(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSArray>, unsigned int, v8::internal::Handle<v8::internal::FixedArrayBase>) [/usr/local/bin/node] 11: 0x100582d51 v8::internal::JSArray::SetLength(v8::internal::Handle<v8::internal::JSArray>, unsigned int) [/usr/local/bin/node] 12: 0x10024c9a6 v8::internal::Accessors::ArrayLengthSetter(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&) [/usr/local/bin/node] 13: 0x100418466 v8::internal::PropertyCallbackArguments::CallAccessorSetter(v8::internal::Handle<v8::internal::AccessorInfo>, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>) [/usr/local/bin/node] 14: 0x10041503c v8::internal::Runtime_StoreCallbackProperty(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node] 15: 0x1009dcb79 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/usr/local/bin/node] 16: 0x39249b3c82ac 17: 0x100962524 Builtins_InterpreterEntryTrampoline [/usr/local/bin/node] [1] 39205 abort node index.js

我電腦運行得到的日志:
{ rss: 1524232192,
  heapTotal: 1509670912,
  heapUsed: 1456969344,
  external: 8272 }

<--- Last few GCs --->
n [13831:0x2719980]    19972 ms: Mark-sweep 1389.5 (1439.7) -> 1389.4 (1439.7) MB, 138.2 / 0.0 ms  (+ 0.0 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 138 ms) (average mu = 0.102, current mu = 0.006) allocation [13831:0x2719980]    20112 ms: Mark-sweep 1389.4 (1439.7) -> 1389.4 (1439.7) MB, 139.3 / 0.0 ms  (+ 0.0 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 140 ms) (average mu = 0.055, current mu = 0.003) allocation 

<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x29dbf095be1d]
Security context: 0x01b54756a5d1 <JSObject>
    1: /* anonymous */ [0xa9e06484c29] [/server/mytest/nodeJsMemoryTest.js:~1] [pc=0x29dbf09fb3c3](this=0x0a9e06484d59 <Object map = 0x3f6dd8882571>,exports=0x0a9e06484d59 <Object map = 0x3f6dd8882571>,require=0x0a9e06484d19 <JSFunction require (sfi = 0xbf6fdec6301)>,module=0x0a9e06484c91 <Module map = 0x3f6dd88d4fd9>,__filename=0x0bf6fdecd261 <String[34]: /...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x8fb090 node::Abort() [node]
 2: 0x8fb0dc  [node]
 3: 0xb0322e v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [node]
 4: 0xb03464 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [node]
 5: 0xef74c2  [node]
 6: 0xef75c8 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [node]
 7: 0xf036a2 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [node]
 8: 0xf03fd4 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [node]
 9: 0xf06c41 v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [node]
10: 0xecfd36 v8::internal::Factory::AllocateRawArray(int, v8::internal::PretenureFlag) [node]
11: 0xed05ba v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::Heap::RootListIndex, int, v8::internal::Object*, v8::internal::PretenureFlag) [node]
12: 0xed0b77 v8::internal::Factory::NewUninitializedFixedArray(int, v8::internal::PretenureFlag) [node]
13: 0xe91a60  [node]
14: 0xe94bf2  [node]
15: 0xe94f52  [node]
16: 0xaf8ec6 v8::internal::Accessors::ArrayLengthSetter(v8::Local<v8::Name>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<v8::Boolean> const&) [node]
17: 0xf6bd57 v8::internal::Runtime_StoreCallbackProperty(int, v8::internal::Object**, v8::internal::Isolate*) [node]
18: 0x29dbf095be1d 
Aborted

 

If you would like to trigger this error, we can run a simple program like:

//index.js const references = []; const allocateSize = (size) => { const numbers = size / 8; const arr = []; arr.length = numbers; for (let i = 0; i < numbers; i++) { arr[i] = i; } return arr; }; while (true) { //steps of 100 const allocation = allocateSize(100 * 1024); //keep in memory so it is not garbage collected references.push(allocation); const usage = process.memoryUsage(); console.log(usage); }
或者:
const array = [];
while (true) {
  // This makes the array bigger on each iteration
  array.push(new Array(10000000));

  const memory = process.memoryUsage();
  console.log((memory.heapUsed / 1024 / 1024 / 1024).toFixed(4), 'GB');
}

 

 

The loop above should run and exhaust the memory limit for your Node.js program.

process.memoryUsage() is used to determine the help size for your proces

How to Work-Around the Memory Limit?

V8 engine comes with a parameter to work around and raise the limit of the heap size through the use of --max-old-space-size , hence to increase your heap memory limit to 2 GB you would do:

node --max-old-space-size=2048 index.js 

This will give you the memory to burn for your expensive usage/calculations for your Node.js process.

You can even go higher for your memory limit:

node --max-old-space-size=1024 app.js # increase to 1gb node --max-old-space-size=2048 app.js # increase to 2gb node --max-old-space-size=3072 app.js # increase to 3gb node --max-old-space-size=4096 app.js # increase to 4gb node --max-old-space-size=5120 app.js # increase to 5gb node --max-old-space-size=6144 app.js # increase to 6gb 

Now you would wonder, how far can I push this limit? 🤔

Theoretically, in a 64-bit system, you can have a heap size of 16 TB of memory, but obviously, you won't be able to each anywhere as close to that. It will be limited by the physical memory limit on the machine and then it will try and leverage the hard disk of the machine to swap data.

How to Increase Memory When You're Using Pm2?

PM2 is a daemon process manager that will help you manage and keep your application online 24/7, which is essential for running applications in a production environment. Sometimes, you want to demonize your application using PM2 but also you would like to allocate a higher memory limit for your application.

To do that PM2 lets you to pass in Node.js arguments when forking a process through the --node-args flag, which can be leveraged to pass in a --max-old-space-size value for your forked process

pm2 start index.js --node-args="--max-old-space-size=1024" # increase to 1gb pm2 start index.js --node-args="--max-old-space-size=2048" # increase to 2gb pm2 start index.js --node-args="--max-old-space-size=3072" # increase to 3gb pm2 start index.js --node-args="--max-old-space-size=4096" # increase to 4gb pm2 start index.js --node-args="--max-old-space-size=5120" # increase to 5gb pm2 start index.js --node-args="--max-old-space-size=6144" # increase to 6gb 

Boom! your application has a lot of room to wiggle around now, and also it is backed up by PM2 a as process monitor for a more robust high-performance production development.

You can see further helpful v8 options and flag by running the command:

node --help --v8-options

 

nodejs診斷內存泄露問題:debugging-a-memory-leak

https://devcenter.heroku.com/articles/node-memory-use

The memory limits of different Node.js versions

There are no official numbers regarding those limits, but with a small program I wrote, I was able to get them for different Node.js versions on a 64bit architecture.

Node Version Limit
15.0.1 4.03 GB
14.15.0 4.03 GB
13.14.0 2.01 GB
12.19.0 2.01 GB
11.15.0 1.34 GB
10.15.3 1.34 GB
9.11.2 1.35 GB

As we can see in this table, the default limits increased with some versions. 4 GB of heap-memory should usually be enough for most use-cases.

You can test this yourself by creating an index.js file with the following code and running it with the Node.js version you want to know the limit for.

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM