[Angular][エラー] JavaScript heap out of memory(ヒープメモリ不足 )
やりたいこと
下記コマンドで、Angularアプリケーションを本番環境でビルドしたい。
ng build --configuration production --source-map
エラー内容
angular# ng build --configuration production --source-map
⠏ Generating browser application bundles (phase: sealing)...
<--- Last few GCs --->
[7954:0x641b0] 241863 ms: Mark-sweep 2009.7 (2085.0) -> 2005.1 (2083.0) MB, 923.9 / 0.1 ms (average mu = 0.771, current mu = 0.186) allocation failure scavenge might not succeed
[7954:0x641b0] 244604 ms: Mark-sweep 2022.3 (2083.0) -> 2020.9 (2113.7) MB, 2660.0 / 0.1 ms (average mu = 0.546, current mu = 0.030) allocation failure scavenge might not succeed
<--- JS stacktrace --->
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
1: 0xb09c10 node::Abort() [ng build --configuration production --source-map]
2: 0xa1c193 node::FatalError(char const*, char const*) [ng build --configuration production --source-map]
原因
原因はエラー内容にもある通り、JavaScriptのヒープ領域がメモリ不足になったことが原因です。
JavaScript heap out of memory
Node.jsを使ってJacaScriptのプロセスを実行しているときに、このエラーが発生することがあります。
このエラーはJavaScriptが処理するプロセスが多く、Node.jsがデフォルトで割り当てているメモリでは実行中のプロセス(この場合ビルド)を終了するのに十分でない場合に発生します。
Nodeなのでnpmコマンドや、Angularであればngコマンドを実行したときに発生する可能性があります。
解決策
JavaScriptのヒープメモリエラーを解決するには、npm/ngコマンドを実行する際に、max-old-space-size
オプションを追加します。
max-old-space-size
オプションにはどれぐらいのメモリを割り当てるか指定できます。
例えばメモリ制限を4GBに増やしたい場合は、下記のように1024にします。(1GB=1024MB)
NODE_OPTIONS="--max-old-space-size=4096"
- 1GB = 1024
- 2GB = 2048
- 3GB = 3072
- 4GB = 4096
💡 ただし、使用可能なメモリを全て使ってしまわないように注意してください。
システムがクラッシュする可能性があります。
よって、今回の場合だと下記のようにすることで処理を通すことができました。
NODE_OPTIONS="--max-old-space-size=4096" ng build --configuration production --source-map
なぜJacaScriptのヒープメモリ不足が発生するのか?
元々Node.jsはデフォルトで、プログラムがメモリを過剰に消費してシステム全体がクラッシュするのを防ぐために、メモリ制限を設けています。
※バージョンやシステムのアーキテクチャ(32bit/64bit)によって違いますが、、。
Node.jsが生まれる前、Web開発におけるJavaScriptの役割は、DOM要素を操作することに限られていました。
しかし、Node.jsのリリース後、JavaScriptはバックエンドのアーキテクチャを持ち、フロントエンドを返す前に、複雑なデータベースクエリーやその他の重い処理を実行することができるようになりました。
また、JavaScriptでは、ReactやAngularなどのライブラリやモジュールをダウンロードできるnpmが台頭してきました。
npmからダウンロードしたモジュールの多くは、他のモジュールとの依存関係が多く、中には使用する前にコンパイルする必要があるものもあります。
Node.jsのメモリ使用量は、処理するタスクが増えるにつれて増加します。
よって、今日のJavaScriptでヒープメモリ不足エラーが発生する場合があります。
まとめ
今回のヒープメモリ不足エラーに対して、一時的にメモリ制限を増やすことで問題を解決しました。
これは場合によっては十分なこともありますが、システムで利用できるメモリが少なかったり、制限を増やしても問題が一時的にしか解決されない場合もあります。
その際は根本的にメモリ管理を解決する必要があります。
参考
Discussion
この問題ですけど2017年ぐらいに自分も同じ問題を解決したことがあります。
そのときはECMAScriptで経験したんですけど問題はNodejsが積んでいるV8のヒープが急激になくなる問題なのでAngular自体で起きている問題ではないです。
ECMAScript使っているBABELやTypeScriptCompilerでも起きる問題なので気をつけてください。