Nodejsメモリ治理

3559 ワード

jsが動作する宿主環境は違っています.メモリの管理に対する要求も違っています.宿主環境がブラウザの場合、ウェブページの運行時間が短いため、ユーザのマシン上だけに運行しています.メモリの使用量が多すぎたり、一定の内部に漏れがあったりしても、端末ユーザに大きな影響を与えることはありません.ホスト環境プログラミングサーバ(Node)の場合、そのコードは固定された何台かのマシン(中国式)で実行されています.また、実行時間は長いです.メモリの管理がうまくいかないと、メモリが膨張したり、メモリが漏れたりすることがあります.サーバー側の応答時間が長くなり、サービスcrashの場合もあります.
NodejsはV 8に基づいて構築されているので、Nodeで使用されるJavaScriptオブジェクトは基本的にV 8によって割り当てられ管理されています.V 8は占有メモリサイズに制約を与えた(64ビットのオペレーティングシステムでは、単一のNodeプロセスで使用できる最大ヒープメモリサイズは約1.5 GB).サーバのメモリが大きくても、V 8の制限により、Nodeはサーバのリソースを十分に利用できなくなります.それでも、なぜV 8はこのような制限をするのですか?このような制限をする原因は実はごみ回収メカニズムと関連しています.1.5 GBのゴミ回収ヒープのメモリヒープを例にとって、V 8は一回の小さなゴミ回収に50 ms以上必要です.一回のゴミ回収をすると1 s以上かかります.ゴミ回収過程でJavaScriptスレッドは実行停止状態にあることを知りたいです.長すぎる暫定時間はバックエンドサービスの性能に大きな影響を与えるので、V 8はこの点を考慮してメモリの積み込みを制限しました.それでもV 8は、メモリサイズをカスタマイズできるようにしてくれます.(--max-old-pace-size)、old-spaceは老生代、new-spaceは新生代を表します.
node --max-old-space-size=xxx index.js  //   MB
//        -max-new-space-size         ,        
メモリの漏洩によってサーバーが頻繁に再起動されている場合、先にメモリの大きさを調整して位置決め問題のために時間を稼ぐことを提案します.結局、サービスの応答が遅いのは、直接エラーページに戻るよりもユーザーにとってもっと受け入れやすいです.
なぜ古い世代と新しい世代が必要ですか?
老生世代と新生代は実は分別式のゴミ回収メカニズムの中の異なっている世代です.ゴミ回収アルゴリズムがないので、すべてのシーンに適任できます.対象の生存周期は違っています.実は回収戦略が必要です.そして、それぞれの世代(新生代、老生代)のメモリにもっと適したアルゴリズムを施す.新生代の対象は生存時間が短いが、老生時代の対象は長く、さらにメモリに常駐している.これに基づいて設計された新生代のメモリは一般的に旧世代のメモリより小さいです.V 8の中で新生代の最大メモリは32 M(64ビットシステムを例にして)、老生世代の最大メモリは140 MBです.V 8が実際に使用しているメモリのサイズは新生代+老生代に使用されたメモリの和(1432 M)であるが、V 8の最大値は実際に使用されているメモリの大きさより32 M(1464 MB)大きくなっている.
新生代はどうやってゴミを回収しますか?
新生代はScaavengeというゴミ回収アルゴリズムを採用しています.Sceavengeの具体的な実現において、主にCheneyアルゴリズムを採用しています.Cheneyアルゴリズムは新生代を二つに分けて、一つはFrom semispaceを使って、一つは暇です.を選択します.対象を作成する場合は、現在のFrom空間で配布しています.ゴミの回収が必要な場合は、From空間の中の生存対象を確認して、生存対象をTo空間にコピーし、From空間を空にして、FromとToを交換します.ゴミ回収の過程で、生存対象を二つのseispaceの間にコピーします.ライフサイクルの短いシーンで生存します.対象は全体の対象の中で比較的に小さいので、Scabiengeは複製生存の対象を採用していますが、Sceavengeはメモリの半分の空間しか利用できません.これは典型的な空間で時間を換える表現です.一つの対象が何回もゴミ回収されます.(普通は二回)生きているとライフサイクルの長い対象とされていますが、新生世代の方が小さく、コピーを繰り返すライフサイクルの長い対象も効率的ではないので、ライフサイクルの長い対象は老生世代に移ります.新生代の対象は老生世代に二つのオブジェクトがあります.1.対象はライフサイクルの長い対象ですか?(ゴミの回収を経験しました)2.Toスペースの使用率は25%を超えていますか?25%制限の原因はゴミの回収が完了したらToがFromになります.制限をしないとfromが早く光を使われることがあります.頻繁にゴミの回収ができ、効率にも影響します.
老生代はどうやってゴミを回収しますか?
高齢者の世代は生存対象が大きな比重を占めているため、生存対象を操作するには適していません.Scangeアルゴリズムを使うのは不適切です.だから、高齢者の世代はMark-SweepとMark-Comppactを結合した方式を採用しました.Mark-Sweepはマークとクリアの二つの段階に分けられています.マークの段階には全ての対象があり、生きている対象をマークして、クリアしてから除外します.消去されます.Mark-Sweepはメモリリリースの問題を解決しましたが、Scafengeのようにオブジェクトをコピーする操作がないため、メモリの断片化が不連続になりました.Mark-comppactはメモリの断片化を解決します.Mark-comppactは生きている対象を端に移動し、移動が完了したら直接に境界外のメモリを消去します.このように、大きな区間の連続利用可能です.V 8は主にMark-Sweepを使用していますが、スペースが足りない場合にのみ、新生代の中で今生来た対象を割り当てる時にMark-Comppactを使用します.
ゴミの回収過程では、アプリケーションの実行が一時停止されます.新生代自体はスペースが小さいため、複製の生存対象が少ないため、全量のゴミ回収を実行しても影響は大きくないです.しかし、老生世代の空間が大きく、生存対象も多く、一回の全量のゴミ回収を実行するのはアプリケーションの一時停止にとっては比較的長い時間です.マークは、マークが完了するまで、マークとアプリケーションが交互に実行されるように、インクリメンタルの更新方法に変更されました.ゴミは回収され、後の清掃作業が実行されます.整理作業は増分されていません.
開発者は強制的にゴミ回収を指定できますか?
答えは大丈夫です.nodeサービスを起動する時に使います.
$ node --expose-gc file.js
このように全体の対象にはゴミ回収を実行する機能があります.
global.gc();
より安全な書き方をおすすめします.
function forceGC()
   if (global.gc) {
      global.gc();
   } else {
      console.warn('No GC hook! Start your program as `node --expose-gc file.js`.');
   }
}
参考資料
https://speakerdeck.com/addyo...http://newhtml.net/v8-garbage…https://www.xarg.org/2016/06/...https://v8project.blogspot.co...https://v8project.blogspot.de...https://v8project.blogspot.it...http://alinode.aliyun.com/blo...