Nodejsのメモリ管理の使用方法

php中世界最好的语言
php中世界最好的语言オリジナル
2018-05-30 10:08:451546ブラウズ

今回は、Nodejs のメモリ管理の使い方と、Nodejs のメモリ管理を使用する際の 注意事項 について説明します。実際の事例を見てみましょう。

ホスト環境がブラウザの場合、Web ページの実行時間は短く、ユーザーのマシン上でのみ実行されるため (分散型に相当)、メモリ使用量が多すぎる場合でも、実行中のホスト環境によってメモリ管理の要件が異なります。または、特定のメモリ リークがエンド ユーザーに大きな影響を与えることはありません。環境プログラミング サーバー (ノード) をホストする場合は状況が大きく異なり、コード自体が少数の固定マシン (集中型) で実行され、メモリ管理が適切でないと実行時間が長くなります。メモリ リークが発生した場合でも、サーバー側の応答時間が長くなったり、サービスがクラッシュしたりすることがあります。

Nodejs は V8 をベースに構築されているため、Node (Buffer ではありません) で使用される

JavaScript オブジェクト は基本的に V8 を通じて割り当ておよび管理されます。 V8 では、占有メモリ サイズに制限が設けられています (64 ビット オペレーティング システムの場合、単一ノード プロセスで使用できる最大ヒープ メモリ サイズは約 1.5 GB)。サーバーに大きなメモリが搭載されている場合でも、V8 のこの制限により、Node はサーバーのリソースを完全に活用できません。それにしても、なぜV8はこのような制限を課さなければならないのでしょうか?この制限の理由は、実際にはガベージ コレクション メカニズムに関連しており、1.5 GB のガベージ コレクション ヒープ メモリ ヒープを例に挙げると、V8 では小さなガベージ コレクションを実行するのに 50 ミリ秒以上かかり、完全なガベージ コレクションを実行するのに 1 秒以上かかる場合もあります。リサイクル処理中は JavaScript スレッドが一時停止状態になる必要があるため、V8 ではバックエンド サービスのパフォーマンスに大きな影響を与えます。ヒープメモリには制限があります。それでも、V8 はヒープ メモリ サイズ (--max-old-pace-size) をカスタマイズする方法を提供しています。ここで、old-space は古い世代を表し、new-space は新しい世代を表します。

node --max-old-space-size=xxx index.js //单位为MB
// 之前还可以通过-max-new-space-size来定义新生代堆大小,现在已经不可以了
メモリ リークが原因でサーバーが頻繁に再起動し続ける場合は、問題を特定する時間を稼ぐために、まずヒープ メモリ サイズを増やすことをお勧めします。結局のところ、サービスの応答が遅い方が、エラー ページを直接返すよりもユーザーにとっては良いのです。

なぜ古い世代と新しい世代が必要なのでしょうか?

世代別ガベージ コレクション メカニズムでは、古い世代と新しい世代は実際には異なる世代です。これは、すべてのシナリオに適したガベージ コレクション アルゴリズムはなく、最良の結果を達成するには、オブジェクトのライフ サイクルが異なると実際に異なるリサイクル戦略が必要になるためです。 V8 では世代別ガベージ コレクション メカニズムが採用されており、オブジェクトは生存時間に応じて異なる世代に分割され、より適切で優れたアルゴリズムが異なる世代 (新世代、旧世代) のメモリに適用されます。

新世代のオブジェクトの生存時間は短くなりますが、古い世代のオブジェクトの生存時間は長くなり、メモリ内に常駐することもあります。これに基づいて設計された新世代のメモリは、一般に旧世代のメモリよりも大幅に小さくなります。V8 の新世代の最大メモリは 32​​M (例として 64 ビット システム)、旧世代の最大メモリです。世代は1400MBです。 V8 で使用される実際のヒープ メモリ サイズは、新世代と旧世代で使用されるメモリの合計 (1432MB) ですが、実際には、V8 の最大値は使用メモリ ペアよりも 32M (1464MB) 大きくなります。新しい世代でガベージコレクションを行うには?

新世代では、Scavenge と呼ばれるガベージ コレクション アルゴリズムが使用されます。 Scavenge の具体的な実装では、主に Cheney アルゴリズムが使用されます。Cheney アルゴリズムは、新世代ヒープを 2 つに分割し、1 つは使用 (セミスペースから)、もう 1 つはアイドル (セミスペースへ) にします。 オブジェクトの作成時は、Fromスペースに割り当てられるようになりました。ガベージコレクションが必要な場合、Fromスペースに残っているオブジェクトがチェックされ、同時にToスペースにコピーされます。 From スペースがクリアされ、From と To が Exchange になり、ガベージ コレクション プロセス全体で、2 つのセイスペース間で残っているオブジェクトがコピーされます。ライフ サイクルが短いシナリオでは、存続するオブジェクトがオブジェクト全体に占める割合は比較的小さいため、Scavenge は存続するオブジェクトのコピーを使用しますが、Scavenge はヒープ メモリ領域の半分しか使用できません。これは、スペースと時間のトレードの典型的な例です。 。

当一个对象经过多次垃圾回收依然存活的话,就会被认为是生命周期较长的对象,一方面新生代堆比较小,另一方面重复复制生命周期长的对象也很没有效率,所以对于生命周期长的对象会被移到老生代中去。新生代对象移动到老生代有两个对象:1.对象是否是生命周期较长的对象(已经经历过垃圾回收)2.To空间使用占比是否超过了25%。限制25%的原因是由于垃圾回收完成后To会变成From,如果不做限制的话可能会出现From很快被用光的情况,出现频繁的垃圾回收,也会影响效率。

老生代如何做垃圾回收?

老生代由于存活对象占较大比重,不适合对存活对象进行操作,使用Scavenge算法就不太合适了,因此老生代采用了Mark-Sweep和Mark-Compact相结合的方式。

Mark-Sweep分为标记和清除两个阶段,在标记阶段遍历堆中所有对象,标记活着的对象,然后在清除阶段未被标记的对象将会被清除掉。Mark-Sweep解决了内存释放的问题但是由于没有像Scavenge那样复制对象的操作导致内存碎片化不连续。而Mark-Compact就是用来解决内存碎片化问题的。Mark-Compact会将存活的对象往一端移动,移动完成后直接清理掉边界外的内存,这样就有大段的连续可用内存了,但是由于涉及到对象的移动,因此Mark-Compact的速度要比Mark-Sweep慢了。V8主要使用Mark-Sweep,只有当空间不足以对新生代中今生过来的对象进行分配时才使用Mark-Compact。

垃圾回收过程中会导致应用程序暂停执行,由于新生代本身空间较小,且要复制的存活对象占比也少,因此即便执行全量垃圾回收也影响不大,但是老生代空间很大,存活对象也多,执行一次全量垃圾回收对于应用程序暂停会是一个比较长的时间,因此V8将老生的标记改成了增量更新的方式,使得标记和应用程序交替执行直到标记完成,然后垃圾回收再执行后面的清理工作。注意清理工作并不是增量的。

开发者可以指定强制垃圾回收吗?

答案是可以了,在启动node服务的时候使用--expose-gc flag

$ 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`.');
 }
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

怎样使用Vue页面骨架屏注入

怎样使用vscode调试编译js代码

以上がNodejsのメモリ管理の使用方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。