私は誤って、node_env!=生産の場合、サーバーで反応がサーバーでレンダリングされると、メモリが漏れることを発見しました。具体的な問題:https://github.com/facebook/react/issues/7406。ノードと反応の同一性やその他の技術の広範な使用により、ノード側のメモリ漏れなどの問題は私たちの注意を引き付けるはずです。ノードはなぜメモリリークが発生し、それが発生した後にトラブルシューティングする方法がありますか?以下は簡単な紹介と例です。
まず、ノードはV8エンジンに基づいており、そのメモリ管理方法はV8と一致しています。以下は、V8の関連するメモリ効果の簡単な紹介です。
V8メモリ制限
ノードはV8に構築されており、V8を介してJSオブジェクトを割り当てて管理できます。 V8には、メモリ使用量に制限があります(古い世代のメモリ64ビットシステムでは約1.4g、32ビットシステムでは約0.7g、新世代のメモリ64ビットシステムでは約32MB、32ビットシステムでは約16MB)。このような制限の下では、大きなメモリオブジェクトは動作できません。この境界が誤って触れた場合、プロセスは終了します。
原因:V8は、Garbage Collectionを実行するときにJavaScriptアプリケーションロジックをブロックし、Garbageコレクションが終了するまでJavaScriptアプリケーションロジックを再実行します。この動作は「停止世界」と呼ばれます。 V8のヒープメモリが1.5GBの場合、V8が小さなゴミコレクションを実行するのに50ミリ秒以上かかり、非節約のガベージコレクションに1秒以上かかります。
Node(Max-Old-Space-Size = XXX(Unit MB)およびNode)およびMax-New-Space-Size = XXX(ユニットKB)を設定することにより、新しい世代のメモリと古い世代のメモリをデフォルトのメモリ制限をクラックするように設定します。
V8ヒープ構成
V8ヒープは、実際には古い世代と新世代の2つの部分で構成されていません。ヒープは、いくつかの異なる領域に分けることができます。
GCリサイクルタイプ
増分GC
ゴミコレクターがメモリスペースをスキャンするときにゴミを収集(追加)するかどうかを示し、スキャンサイクルの終わりにゴミをクリアするかどうかを示します。
非増殖GC
非包帯のゴミコレクターを使用する場合、ゴミは収集されるとすぐに空になります。
ゴミコレクターは、新世代のメモリエリア、旧世代ポインターエリア、旧世代データエリアのみのゴミコレクションのみを実施します。オブジェクトは、まず、スペースが少ない新しい世代のメモリに入ります。ほとんどのオブジェクトは迅速に失敗し、非節約型GCはこれらの少量のメモリを直接リサイクルします。一部のオブジェクトを一定期間リサイクルできない場合、それらは古い世代の記憶領域に入力されます。この領域は、まれな増分GCを実行し、長い時間がかかります。
次に、メモリリークはいつ発生しますか?
メモリリークパス
ノードのメモリ構成は、主にV8を介して割り当てられた部分とノード自体によって割り当てられた部分です。 V8のゴミコレクションの主な制限は、V8のヒープメモリです。メモリリークの主な理由:1。キャッシュ。 2。キューの消費はタイムリーではありません。 3。スコープがリリースされていません
メモリリーク分析
V8メモリの使用(ユニットバイト)を確認する
process.memoryusage(); {ress:47038464、heptotal:34264656、盛り:2052866}Ress:プロセスの常駐メモリ部分
積み上げ、盛り上がり:V8ヒープメモリ情報
システムメモリ使用(ユニットバイト)を確認する
os.totalmem()
os.freemem()
合計システムメモリとアイドルメモリを返します
ガベージコレクションログを表示します
node -trace_gc -e "var a = []; for(var i = 0; i <1000000; i ++){a.push(new Array(100));}" >> gc.log //出力ガーバーコレクションログ
ノード-Prof //出力ノード実行パフォーマンスログ。 Windows-Tick.Processorを使用して表示します。
分析的監視ツール
V8プロフィラーはV8ヒープメモリのスナップショットをキャプチャし、CPUを分析します
Node-Heapdumpは、V8ヒープメモリのスナップショットをつかみます
ノード-MTRACE分析スタックの使用
ノードメムウォッチは、ゴミ収集の状況に耳を傾けます
ノードメムウォッチ
memwatch.on( 'stats'、function(info){console.log(info)})memwatch.on( 'leak'、function(info){console.log(info)})統計イベント:フルヒープガベージコレクションが実行されるたびに、統計イベントがトリガーされます。このイベントはメモリ統計を渡します。
{"num_flull_gc":17、//フルスタックのガベージコレクション数 "num_inc_gc":8、//何回のガベージコレクション「heap_compactions ":8、//古い世代が並べ替えられた" atmated_base ":2592568:// "min":2499912、//最小 "max":2592568、//最大 "usage_trend":0 //ユーザートレンド}num_full_gcとnum_inc_gcを観察して、ゴミコレクションを反映します。
リークイベント:5つの連続したゴミコレクションの後にメモリがまだリリースされていない場合、それはメモリリークが発生することを意味します。今回はリークイベントがトリガーされます。
{開始:2012年6月29日14:12:13 GMT、終了:金曜日、2012年6月29日14:12:33 GMT、成長:67984、理由: '5連続GCS(20S)-11.67 MB/HR'}にわたるヒープ成長ヒープディフのヒープメモリ比較トラブルシューティングメモリオーバーフローコード。
以下に、例を使用して、メモリの漏れをトラブルシューティングする方法を示します。
最初に、メモリリークを引き起こす例を作成します。
//app.jsvar app = require( 'express')(); var http = require( 'http')。server(app); var heapdump = require( 'heapdump'); function leakclass(){this.x = 1;} appget( '); forq、resole.log); 0; I ++){new leakclass()} 3000); http.listen(3000、function(){console.log( 'listening on port 3000');});ここでは、絶えず増加しており、取得しない配列をセットアップすることにより、メモリリークをシミュレートします。
ヒープダンプモジュールを使用して、メモリスナップショットを定期的に記録し、比較と分析のためにChrome開発者ツールプロファイルを介してスナップショットをインポートします。
ブラウザがLocalHost:3000にアクセスし、何度もリフレッシュした後、スナップショットのサイズが増えており、要求されていなくても減少せず、漏れが発生したことを示しています。
次に、Chrome開発者ツールプロファイルを介してスナップショットをインポートします。比較を設定することにより、最初のスナップショットを比較し、リクエストを送信し、リクエストを送信して、これら3つの段階でメモリスナップショットを送信します。リーククラスが右側の新しいもので増加していることがわかります。デルタでは常に肯定的であり、それはリサイクルされていないことを意味します。
まとめ
メモリリークの場合、Memwatchを使用してインプラントを使用したり、Process.MemoryUsageメモリ使用量を報告して定期的に監視したり、監視用のアラームしきい値を設定したりできます。
メモリリークが見つかった場合、許可されている場合は、ノードヒープダンプをローカルで実行し、生成するタイミングメモリスナップショットを使用できます。スナップショットを使用して、クロムプロファイルを介した漏れの原因を分析します。ローカルデバッグが不可能な場合は、V8-Profilerを使用してテストサーバーにメモリスナップショットを出力して、JSONを比較および分析します(コード侵入が必要です)。
どのような状況を考慮すべきか、Memwatch/Heapdumpが有効になります。 CPUが不足しないように、Heapdumpの頻度を考慮してください。 MemoryUsage()を直接監視するなど、メモリの成長を検出する他の方法も考慮することができます。
誤判断に注意してください。短期のメモリ使用量のピークは、メモリリークのように振る舞います。アプリが突然多くのCPUとメモリを消費する場合、処理時間はいくつかのガベージコレクションサイクルに及ぶ可能性があり、その後、Memwatchはそれをメモリリークとして誤って審判する可能性があります。ただし、この場合、アプリがこれらのリソースを使用すると、メモリ消費は通常のレベルに戻ります。そのため、メモリリークが継続的に報告されており、1つまたは2つの突然のアラームを無視できることに注意することが重要です。