ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう

Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう

青灯夜游
青灯夜游転載
2022-11-29 20:44:082108ブラウズ

ノード GC (ガベージ コレクション) はどのように機能しますか?次の記事で詳しく説明します。

Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう

GC、ガベージ コレクション、ガベージ コレクション。プログラミングでは、これは一般に、不要なデータを定期的に消去する自動メモリ リサイクル メカニズムを指します。

Node.js はその下で V8 エンジンを使用します。 V8 は、Google がオープンソース化した C で書かれた高性能 JavaScript エンジンです。 [関連チュートリアルの推奨事項: nodejs ビデオ チュートリアル ]

Node.js のメモリは主に 3 つの部分に分かれています:

  • コード スペース: ここでコード セグメントは格納されます 場所;

  • スタック: 関数呼び出しスタックによって生成される一時変数で、数値、文字列、ブール値、オブジェクト参照 (アドレスなど) などの基本的な型です。は保存されますが、オブジェクト自体は保存されません)。

  • ヒープ: オブジェクトとその他のデータを保存します。

ヒープ メモリ

基盤となる Node.js使用方法 それは V8 です V8 のメモリ再利用の仕組みを説明しましょう。

まず、JS 内のすべてのオブジェクトはヒープ メモリに保存されます。プロセスが作成されると、初期サイズのヒープ メモリが割り当てられ、その中にオブジェクトが配置されます。

オブジェクトが増えると、ヒープ メモリが足りなくなり、ヒープ メモリが動的に拡張されます。最大制限 (現在では通常 4 GB) に達すると、ヒープ オーバーフロー エラーが発生し、Node.js プロセスが終了します。

新世代と旧世代

V8 はまずメモリを 2 つの部分、つまり 2 つの世代に分割します。

  • 若い世代: 短い生存時間で一部のオブジェクトを保存します;

  • 旧世代 (旧世代): 長い生存時間または長期永続性でオブジェクトを保存します。

新しい世代は非常に小さく、生存時間の短いいくつかのオブジェクトがここに保存されます。これらは通常、頻繁にリサイクルされます (関数の呼び出しスタック内の一部の一時オブジェクトなど)。

新しい世代のサイズは、node --max-semi-space-size=SIZEindex.js を通じて変更できます。単位は MB です。

さらに、古い世代は --max-old-space-size=SIZE を使用して、新しい世代の

スカベンジ アルゴリズムを設定します。世代

新しい世代では、コピーに基づくアルゴリズムであるスカベンジ アルゴリズムが使用されます。

新しい世代は 2 つのスペースに分割されます。このスペースはセミスペースと呼ばれます。それらは次のとおりです:

  • スペースから: 新しく宣言されたオブジェクトはここに配置されます

  • To スペース: 再配置に使用されるスペース

新しく宣言されたオブジェクトは From スペースに配置され、From スペース内のオブジェクトは密に配置されます。ポインタでは、前のオブジェクトは次のオブジェクトに近く、メモリは連続しているため、メモリの断片化を心配する必要はありません。

いわゆるメモリの断片化とは、不均一なスペース割り当てを指し、その結果、大きなオブジェクトに収まらない小さな連続スペースが多数発生します。

From スペースがほぼいっぱいになったら、トラバースしてアクティブなオブジェクトを見つけ、それらを To スペースにコピーします。この時点では、From スペースは実際には空であるため、From と To の ID を交換します。

一部のオブジェクトが複数回コピーされた場合、それらのオブジェクトは存続期間が長いとみなされ、古い世代に移動されます。

このコピーベースのアルゴリズムの利点は、メモリの断片化の問題をうまく処理できることです。欠点は、移動空間の場所としてスペースを無駄にすることです。また、コピーには時間がかかるため、メモリ空間は補助的な GC のようなものであり、大きすぎる割り当てには適していません。

マーク スイープとマーク コンパクト

旧世代のスペースは新世代のスペースよりもはるかに大きく、長期にわたって存続するオブジェクトがいくつか含まれています。マークスイープ (マーク除去) アルゴリズムが使用されます。

最初はマーキング段階です。ルート セットからアクセス可能なすべてのオブジェクト (実行スタックおよびグローバル オブジェクト) を検索し、アクティブ オブジェクトとしてマークします。

マークを付けた後、クリア フェーズになります。マークされていないオブジェクトをクリアすると、実際にはメモリ アドレスが空きとしてマークされます。

このアプローチは、空きメモリ空間の断片化につながります. 大きな連続オブジェクトを作成すると、それを置く場所が見つからなくなります。このとき、断片化したアクティブオブジェクトを統合するには、Mark-Compact (マークコンパクション) を使用する必要があります。

Mark-Compact は、すべてのアクティブなオブジェクトのコピーを一方の端に移動し、境界の反対側は連続した使用可能なメモリのブロック全体になります。

Mark-スイープとマーク-コンパクトは時間がかかり、JavaScript スレッドをブロックすることを考慮して、通常は一度にすべてを実行せず、増分マーキング (増分マーキング) を使用します。つまり、断続的にマークを付け、小さなステップを踏み、ガベージ コレクションとアプリケーション ロジックを交互に実行する必要があります。

さらに、V8 では、実行効率を向上させるために、並行マーキングと並行クリーニングも実行されます。

Node.js の GC (ガベージ コレクション) メカニズムについて話しましょう

#メモリ関連情報の表示

process.memoryUsage メソッドを通じてメモリ関連の情報を取得できます。

process.memoryUsage();

出力内容は次のとおりです:

{
  rss: 35454976,
  heapTotal: 7127040,
  heapUsed: 5287088,
  external: 958852,
  arrayBuffers: 11314
}

Description

  • rss: 常駐セット サイズ (常駐セット サイズ)。コード スニペット、ヒープ メモリ、スタックとその他の部品。

  • heapTotal: V8 の合計ヒープ メモリ サイズ;

  • heap Used: 占有されているヒープ メモリ;

  • external: V8 以外のメモリ サイズは、バッファ データなどの C オブジェクトによって占有されるメモリを指します。

  • arrayBuffers: 外部の一部である

    ArrayBuffer および SharedArrayBuffer に関連するメモリ サイズ。

上記の数値の単位はバイトです。

最大メモリ制限をテストする

スクリプトを作成し、タイマーを使用し、配列を継続的に増加させ、メモリがオーバーフローするまでのヒープ メモリ使用量を出力します。

const format = function (bytes) {
  return (bytes / 1024 / 1024).toFixed(2) + " MB";
};

const printMemoryUsage = function () {
  const memoryUsage = process.memoryUsage();
  console.log(
    `heapTotal: ${format(memoryUsage.heapTotal)}, heapUsed: ${format(
      memoryUsage.heapUsed
    )}`
  );
};

const bigArray = [];
setInterval(function () {
  bigArray.push(new Array(20 * 1024 * 1024));
  printMemoryUsage();
}, 500);

テストに Buffer を使用しないように特別な注意を払う必要があります。

Buffer は Node.js に固​​有のバイナリ オブジェクトであるため、V8 には実装されていません。C の Node.js によって別途実装されます。V8 を通じてメモリを割り当てず、オフヒープ メモリに属します。 。

私が使用しているコンピューターは macbook pro M1 Pro、Node.js バージョンは

v16.17.0、使用されている V8 バージョンは 9.4.146.26-node.22 (経由) process.versions .v8 が取得します)。

出力結果は次のとおりです (一部の冗長な情報は省略しています):

heapTotal: 164.81 MB, heapUsed: 163.93 MB
heapTotal: 325.83 MB, heapUsed: 323.79 MB
heapTotal: 488.59 MB, heapUsed: 483.84 MB
...
heapTotal: 4036.44 MB, heapUsed: 4003.37 MB
heapTotal: 4196.45 MB, heapUsed: 4163.29 MB

<--- Last few GCs --->

[28033:0x140008000]    17968 ms: Mark-sweep 4003.2 (4036.4) -> 4003.1 (4036.4) MB, 2233.8 / 0.0 ms  (average mu = 0.565, current mu = 0.310) allocation failure scavenge might not succeed
[28033:0x140008000]    19815 ms: Mark-sweep 4163.3 (4196.5) -> 4163.1 (4196.5) MB, 1780.3 / 0.0 ms  (average mu = 0.413, current mu = 0.036) allocation failure scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
...

4000 MB を超えるとメモリ制限を超え、ヒープ オーバーフローが発生し、プロセスが終了することがわかります。私のマシンでは、デフォルトの最大メモリが 4G であることに注意してください。

実際の最大メモリは、実行されるマシンに関係します。マシンのメモリ サイズが 2G の場合、最大メモリは 1.5G に設定されます。

ノード関連の知識の詳細については、

nodejs チュートリアル を参照してください。

以上がNode.js の GC (ガベージ コレクション) メカニズムについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。