nodejsのメモリオーバーフロー致命的なエラー:CALL_AND_RETRY_0割り当てに失敗しました–プロセスのメモリ不足(再現)
Nodejs Memory Overflow Fatal Error
Nodejsメモリオーバーフローエラー致命的なエラー:CALL_AND_RETRY_0割り当てに失敗しました–プロセスのメモリが不足しています
1〜12
エラーを報告する
致命的なエラー:CALL_AND_RETRY_0割り当てに失敗しました–プロセスのメモリが不足しています
キューを使用していたときに、大きな配列を実行しましたが、実行の途中でメモリオーバーフローが発生することがよくありました。
いくつかの解決策を確認し、一時的にこのように解決します
--max-old-space-size=
を渡すことで、デフォルトの制限を増やすことができます。これはMB単位です。
この例では、ノードのヒープで最大4 GB(4096)を使用できます。 メガバイト )メモリの:
node --max-nex-space-size=1024 app.js // The unit is KB node --max-old-space-size=2000 app.js // The unit is MB
同様の問題
http://stackoverflow.com/questions/7357339/nodejs-out-of-memory
http://cnodejs.org/topic/500904be4764b72902d30f4d
http://www.360doc.com/content/14/0903/22/11644963_406872841.shtml
Yunqi分析ソリューション
https://yq.aliyun.com/articles/4050
解決
http://stackoverflow.com/questions/7357339/nodejs-out-of-memory
http://www.tuicool.com/articles/miU3e2
http://www.360doc.com/content/14/0903/22/11644963_406872841.shtml
Pu Lingが言ったように、Nodeはメモリリークに非常に敏感です。オンラインアプリケーションに数千のトラフィックがあると、1バイトのメモリリークでも蓄積が発生し、ガベージコレクションプロセスにさらに時間がかかります。オブジェクトのスキャンでは、アプリケーションの応答が遅くなり、プロセスメモリがオーバーフローするまで、アプリケーションがクラッシュします。
メモリの問題は無視できないことが長い間知られていましたが、日常の開発中にパフォーマンスのボトルネックはありません。最近まで、100万PVレベルのマーケティングプロジェクトが行われていました。訪問数が多かったため、同時ボリュームは1に達しました。マグニチュード。いくつかの小さな、目立たない問題が拡大され、それから彼らは見えてきて、記憶の問題に気づき始めました。 Nodeがメモリリークに非常に敏感であることをほとんど知りません。
そのために、V8のメモリ処理メカニズムについて急いで学びました。
では、V8のメモリメカニズムは何ですか?
V8のメモリメカニズム
メモリ制限
他のバックエンド言語とは異なり、Nodeにはメモリ使用量に関する多くの制限がありません。ノードでメモリを使用する場合、システムメモリの一部のみを使用できます。 64ビットシステムの場合は約1.4GB、32ビットシステムの場合は0.7GBです。これは、ノードが元々ブラウザで実行されていたV8エンジンを使用しているためです。
V8エンジンは、最初はブラウザーで実行するように設計されていましたが、ブラウザーの一般的なアプリケーションシナリオで使用するには十分であり、フロントエンドページのすべての要件を満たすだけで十分です。
大容量メモリのサーバー側操作は一般的な要件ではありませんが、そのような要件がある場合は、制限を解除できます。ノードプログラムを起動するときに、2つのパラメータを渡して、メモリ制限のサイズを調整できます。
--max-old-space-size
これらの2つのコマンドは、それぞれノードメモリヒープの「新世代」と「旧世代」に対応します。
記憶に制限されない特別な場合
Nodeでは、Bufferを使用すると、V8のメモリ制限を超える大きなファイルを読み取ることができます。その理由は、BufferオブジェクトがV8メモリ割り当てメカニズムを通過しないという点で他のオブジェクトとは異なるためです。これはNodeのアプリケーションシナリオであり、ブラウザとは異なります。ブラウザでは、JavaScriptはほとんどのビジネスニーズを満たすために文字列を直接処理できますが、ノードはネットワークストリームとファイルI / Oストリームを処理する必要があります。ストリングの操作は、伝送のパフォーマンス要件を満たすにはほど遠いです。
メモリ割り当て
すべてのJavaScriptオブジェクトはヒープに保存されます
変数を宣言してコードで値を割り当てると、使用されるオブジェクトのメモリがヒープに割り当てられます。割り当てられた空きメモリが新しいオブジェクトを割り当てるのに十分でない場合は、ヒープサイズがV8の制限を超えるまで、ヒープメモリの申請を続けます。
V8のガベージコレクションメカニズム
世代別ガベージコレクション
V8のガベージコレクション戦略は、主に「世代別ガベージコレクションメカニズム」に基づいています。このメカニズムに基づいて、V8はメモリを「新しいスペース」と「古いスペース」に分割します。
若い世代のオブジェクトは生存時間が短いオブジェクトであり、古い世代のオブジェクトは生存時間が長いオブジェクトまたは永続的なメモリです。
前に述べた--max-new-space-size
コマンドは、旧世代の最大メモリスペースを設定することです。var heapdump = require('node-heapdump')
コマンドは、新世代のメモリスペースのサイズを設定できます。
なぜ2世代に分かれているのですか?
ガベージコレクションアルゴリズムにはさまざまな種類がありますが、すべてのシナリオに適しているわけではありません。実際のアプリケーションでは、最良の結果を得るには、オブジェクトのライフサイクルに応じてさまざまなアルゴリズムを使用する必要があります。 V8では、メモリのガベージコレクションは、オブジェクトの存続時間に応じてさまざまな世代に分割され、より効率的なアルゴリズムがさまざまなメモリに適用されます。
新世代のガベージコレクション
新世代では、主に スカベンジ ガベージコレクションのアルゴリズム。
スカベンジ
Scavengeアルゴリズムでは、ヒープメモリを2つに分割し、スペースの各部分をセミスペースと呼びます。 2つのセミスペーススペースのうち、1つだけが使用中で、もう1つはアイドル状態です。使用中のセミスペースはFromスペースと呼ばれ、アイドル状態のセミスペースはToスペースと呼ばれます。オブジェクトを割り当てるときは、最初にFromスペースからオブジェクトを割り当てます。ガベージコレクションが開始されると、Fromスペースに残っているオブジェクトがチェックされます。これらの生き残ったオブジェクトはToスペースにコピーされ、生き残っていないオブジェクトが占めていたスペースが解放されます。コピーが完了すると、FromスペースとToスペースの役割が交換されます。つまり、ガベージコレクションの過程で、ライブオブジェクトは2つのセミスペーススペース間でコピーされます。
若い世代のオブジェクトはどのようにして古い世代に移行できますか?
若い世代で生存期間が長いオブジェクトは、主に次の2つの条件のいずれかを満たす古い世代に移動されます。
1.被験者がスカベンジ回復を経験したかどうか。
オブジェクトがFromスペースからToスペースにコピーされると、オブジェクトはそのメモリアドレスをチェックして、オブジェクトがScavengeコレクションを受けたかどうかを判断します。存在する場合、オブジェクトはFromスペースから旧世代スペースにコピーされます。
2. Toスペースのメモリ比率が25%の制限を超えています。
オブジェクトがFromスペースからToスペースにコピーされるときに、Toスペースが25%を超えて使用されている場合、オブジェクトは古い世代に直接コピーされます。これは、Scavengeリカバリが完了した後、ToスペースがFromスペースになり、次のメモリ割り当てがこのスペースで実行されるためです。比率が高すぎると、後続のメモリ割り当てが影響を受けます。
旧世代のガベージコレクション
古い世代のオブジェクトの場合、生き残ったオブジェクトが大きな割合を占めるため、Scavengeアルゴリズムを使用することは明らかに非科学的です。第一に、コピーしすぎるオブジェクトは効率の問題を引き起こし、第二に、2倍のスペースを浪費します。したがって、旧世代では、V8は主に「Mark-Sweep」アルゴリズムと「Mark-Compact」アルゴリズムの組み合わせをガベージコレクションに使用します。
マークスイープ
マークスイープとは、マークのクリアを意味し、マークとクリアの2つの段階に分けられます。マーキングフェーズでは、ヒープ内のすべてのオブジェクトがトラバースされ、残っているオブジェクトがマークされます。次のクリーニングフェーズでは、マークの外側のオブジェクトのみが削除されます。
しかし、マークスイープには非常に深刻な問題があります。つまり、マークスイープとリサイクルの後、メモリが断片化されます。大きなオブジェクトを割り当てる必要がある場合、現時点では割り当てを完了できません。 Mark-Compactをプレイする時が来ました。
マーク-コンパクト
Mark-Compactは、Mark-Sweepに基づいて進化したマーク仕上げを意味します。 Mark-Compactは、生き残ったオブジェクトにマークを付けた後、並べ替えプロセス中に生き残ったオブジェクトを一方の端に移動します。移動が完了すると、境界の外側のメモリが直接クリアされます。
インクリメンタルマーキング
Nodeのシングルスレッドの性質を考慮して、V8は、ガベージコレクションが行われるたびにアプリケーションロジックを一時停止し、ガベージコレクションの実行後にアプリケーションロジックを再開する必要があります。これは「フルポーズ」と呼ばれます。世代別ガベージコレクションでは、小さなガベージコレクションは若い世代のみを収集し、存続するオブジェクトは比較的少なく、完全に停止してもあまり影響はありません。ただし、旧世代では、多くのオブジェクトが残っており、ガベージコレクションのマーキング、クリーニング、および並べ替えには長い休止が必要であり、システムのパフォーマンスに深刻な影響を及ぼします。そこで、「インクリメンタルマーキング」が提案されました。マーキング段階から始まり、停止時に完了するはずだったアクションをインクリメンタルマーキングに変更し、それを多くの小さな「ステップ」に分割します。各「ステップ」の後、JavaScriptアプリケーションロジックが短時間実行されます。リサイクルとアプリケーションロジックは、マーキングフェーズが完了するまで、この方法で交互に実行されます。
メモリリークのトラブルシューティングツール
node-heapdump
事後分析のためにV8ヒープメモリのスナップショットを撮ることができます。プログラムで紹介する
$ kill -USR2
その後、SIGUSR2シグナルをサーバーに送信して、node-heapdumpにヒープメモリのスナップショットを取得させることができます。
node --max-old-space-size=4096 app
このスナップショットは、デフォルトでファイルディレクトリに保存されます。これは、Chromeの開発者ツールで開いて表示できる大きなJSONファイルです。
node-memwatch
node-memwatchはノードv0.12.xまでしかサポートしないことに注意してください。より高いバージョンを使用する場合、それはインストールされません。あなたはそれを使うことができます node-watch-next 代替の、まったく同じAPI。
node-heapdumpとは異なり、メモリリークとガベージコレクションに関する情報を提供する2つのイベントリスナーを提供します。
-
statsイベント:フルヒープコレクションが実行されるたびに、時間が変更され、メモリの統計が送信されます
-
リークイベント:5回のガベージコレクションの後、メモリがまだ解放されていない場合、リークイベントがトリガーされ、関連情報が転送されます。
ノードプロファイル
node-profilerは、alinodeチームによって作成されたメモリヒープスナップショットを取得するためのnode-heapdumpに似たツールです。違いは、node-profilerの実装が異なり、使用する方が便利なことです。彼らのチュートリアルを添付してください: NodeProfilerの使用方法
アリノード
公式のアリノードは言った:
Alinodeは、AlibabaCloudによって作成されたNode.jsアプリケーションサービスソリューションです。これは、コミュニティノードに基づいて改善されたランタイム環境とサービスプラットフォームのセットです。コミュニティに基づいて、開発者がパフォーマンスの詳細をすばやく洞察し、難治性の病気をすばやく見つけ、問題の根本を直接調査できるようにする強力なサポート機能を構築しました。
上記の内容はから参照されています
著作権は以下に属します: SETPHP