JavaScript のガベージコレクションの仕組みの詳細な説明

JavaScript のガベージコレクションの仕組みの詳細な説明

ガベージコレクション (GC) はなぜ必要なのでしょうか?

  • プログラムは人間と同じです。時間の経過とともにゴミが生成されます。プログラムも動作中にゴミを生成します。ゴミが蓄積しすぎると、プログラムの実行速度が低下します。
  • JavaScript の文字列、オブジェクト、配列などのデータのメモリは固定されておらず、実際に使用されるときにのみメモリが動的に割り当てられます。
  • これらのデータによって占有されているメモリは、使用されていないときに解放して再度使用できるようにする必要があります。そうしないと、使用可能なメモリが使い果たされたときにプログラムがクラッシュします。

ガベージコレクションとは

ガベージ コレクション メカニズムはGarbage Collection (略して GC) とも呼ばれます。 JavaScript には、リサイクル アルゴリズムを使用して使用されなくなった変数やプロパティを見つける自動ガベージ コレクション メカニズムがあり、JS エンジンは一定の時間間隔でそれらが占有しているメモリ領域を定期的に解放します。 C/C++ では、プログラマーが手動でガベージ コレクションを実行する必要があります。

廃棄物の発生

オブジェクトに参照する変数やプロパティがない場合、そのオブジェクトを操作することはできません。このオブジェクトはゴミです。このようなオブジェクトが多すぎると、大量のメモリ領域を占有し、プログラムの速度が低下します。

例えば:

ここに画像の説明を挿入

ここで、まず Person 変数を宣言し、この変数はオブジェクト {name: "江流", age: 20} を参照します。次に、この Person 変数を別のオブジェクト {name: "心猿", age: 5000} にポイントします。以前参照していたオブジェクトは、これで役に立たないオブジェクトになり、操作に使用することはできません。このようなオブジェクトはゴミです。

ガベージ オブジェクトが多すぎると、多くのスペースを占有します。ガベージ オブジェクトが解放されないと、システムのパフォーマンスに影響し、プログラムがクラッシュすることもあります。そのため、このメモリ部分を解放するにはガベージ コレクションが必要です。

このプロセスではガベージ コレクションを実行する必要はなく、実行することもできません。

必要なのは、使用されなくなったオブジェクトを null に設定することだけです。

ガベージコレクション戦略

JavaScript におけるメモリ管理の主な概念は到達可能性です。大まかに言えば、何らかの方法でアクセスまたは使用できる値はメモリ内に保持する必要があり、アクセスまたは使用できない値はガベージ コレクション メカニズムによってリサイクルされる必要があることを意味します。

JavaScript はシングルスレッド言語であるため、ガベージ コレクション プロセスはリアルタイムで実行されません。ガベージ コレクションが実行されるたびに、プログラムのアプリケーション ロジックが一時停止されます。ガベージ コレクションが完了すると、アプリケーション ロジックが再度実行されます。この動作は完全一時停止と呼ばれ、ガベージ コレクションは一般に CPU がアイドル状態のときに実行されます。

いわゆるガベージを何らかの方法で見つける方法がガベージ コレクションの焦点であるため、次のような一般的なアルゴリズム戦略がありますが、ここでは最初の 2 つについてのみ説明します。

  1. 参照カウントアルゴリズム
  2. マークアンドスイープアルゴリズム
  3. タグの並べ替え
  4. 世代間のリサイクル

参照カウントタグ

戦略的思考:

  • 各変数値が何回使用されたかを追跡する
  • 変数が宣言され、その変数に参照型データが割り当てられると、参照型データの参照カウントは 1 としてマークされます。
  • この参照型データを別の変数に割り当てると、参照数は +1 になります。
  • 変数が別の値によって上書きされた場合、参照カウントは -1 になります。
  • この参照型データの参照カウントが 0 になると、変数は使用されなくなり、アクセスできなくなります。ガベージ コレクターは、実行中に参照カウントが 0 の参照型データを破棄し、占有していたメモリ領域を再利用します。

例えば:

	a = {とする
	    名前: 「江劉」
	    年齢: 20
		}; //この時点でオブジェクトの参照カウントは 1 (参照) としてマークされます
	let b = a; //この時点でオブジェクトの参照カウントは 2 (a、b 参照) とマークされます
	a = null; //この時点でオブジェクトの参照カウントは 1 としてマークされます ((b 参照))
	b = null; //この時点でオブジェクトの参照カウントは 0 としてマークされます (変数参照なし)
	... //GCがこのオブジェクトを回収するまで待機します

しかし、このアプローチには深刻な問題がある。循環参照である。

循環参照によって生じる問題

関数では、オブジェクト A のプロパティはオブジェクト B を指し、オブジェクト B のプロパティはオブジェクト A を指します。関数が実行されると、オブジェクト A と B のカウンターは 0 ではなくなり、通常の GC に影響します。

たとえば、次の例をご覧ください。

関数テスト()
{
    A = new Object();
    B = 新しいオブジェクト();
    A.ポインタ = B;
    B.ポインタ = A;
}
テスト();

オブジェクト A とオブジェクト B のプロパティが相互に参照する場合、参照カウント戦略によれば、それらの参照カウントは両方とも 2 になります。ただし、test() が実行された後、関数が実行された後、関数スコープ内のデータ オブジェクト A と B は GC によって破棄される必要があります。

複数回実行すると、重大なメモリリークが発生します。

回避策

関数の最後にnullを設定します

// 参照関係を切断します A = null;
B = ヌル;

参照カウントアルゴリズムの利点と欠点

アドバンテージ:

  • 参照カウントがゼロになると、ガベージはすぐに収集されます
  • プログラムの一時停止を最小限に抑える

欠点:

  • 循環参照オブジェクトを再利用できません
  • 大きなスペースコスト

マークアンドスイープアルゴリズム

コアアイデア

マーキングとクリアの 2 つのフェーズで完了します。

おおよそのプロセス:

  • ガベージ コレクターは、実行時にメモリ内のすべての変数にマークを追加します。メモリ内のすべてのオブジェクトがガベージであると仮定すると、すべて 0 としてマークされます。
  • 次に、各ルートオブジェクトからトラバースを開始し、ガベージではないノードを1に変更します。
  • 0 としてマークされたすべてのゴミをクリーンアップし、それらが占めるメモリ領域を破壊して再利用します。
  • 最後に、メモリ内のすべてのオブジェクトのマークを 0 に変更し、次のガベージ コレクション ラウンドを待機します。

ここに画像の説明を挿入

マークスイープアルゴリズムの利点と欠点

アドバンテージ:

  • 実装は簡単です。マーキング状況は、ヒットするかヒットしないかの 2 つの状況のみです。これらはバイナリ (0 と 1) でマークできます。
  • 循環参照を持つオブジェクトをリサイクルする機能
  • これは、v8 エンジンで最も一般的に使用されるアルゴリズムです。

欠点:

ガベージ コレクション後、残りのオブジェクトのメモリ位置は変更されず、空きメモリ領域が不連続になります。これによりメモリの断片化が発生し、残りのスペースがブロック全体ではなくなるため、メモリの割り当てが問題になります。

マークスイープアルゴリズム

Mark-Compact アルゴリズムは、この問題を効果的に解決できます。Mark-Compact アルゴリズムは、マークを付けた後、クリーンアップする必要のないオブジェクトをメモリの一方の端に移動し、最後に境界でメモリをクリーンアップします。

ここに画像の説明を挿入

V8エンジンのガベージコレクション

  • V8エンジンのガベージコレクションはマークスイープと世代別コレクション方式を採用している。
  • 新世代と旧世代に分かれる

オブジェクトごとに異なるアルゴリズムを使用します。

(1)新世代:オブジェクトの生存時間が短くなります。新しいオブジェクト、または一度だけガベージ コレクションされたオブジェクト。

(2)古い世代:オブジェクトはより長く存続する。 1 回以上のガベージ コレクションを経たオブジェクト。

新世代のオブジェクトのリサイクル

新世代のオブジェクトは、主にコピー アルゴリズム (Scavenge アルゴリズム) とマーク スイープ アルゴリズムを使用してリサイクルされます。 Scavenge アルゴリズムの具体的な実装では、主に Cheney アルゴリズムが使用されます。

オブジェクト昇格メカニズム

GC ラウンドを生き残った新世代を昇格させる必要があります。

古い世代のオブジェクトのリサイクル

マークスイープ、マークコンパクト、増分マークの各アルゴリズムは、主に古い世代のオブジェクトをリサイクルするために使用されます。マークスイープアルゴリズムは主に使用され、マークコンパクトアルゴリズムはメモリ割り当てが不十分な場合にのみ使用されます。

  • まず、mark-sweep を使用してガベージ スペースの回復を完了します。
  • マークアップを使用してスペースを最適化します。
  • 効率を最適化するために増分マーキングを使用します。

参考資料:

JS ガベージコレクションメカニズム

JavaScript GC ガベージコレクションのメカニズム

要約する

この記事はこれで終わりです。皆さんのお役に立てれば幸いです。また、123WORDPRESS.COM のその他のコンテンツにも注目していただければ幸いです。

以下もご興味があるかもしれません:
  • js クロージャとガベージ コレクション メカニズムの例の詳細な説明
  • JavaScript におけるガベージ コレクションとメモリ リークの詳細な例
  • JavaScriptのガベージコレクションの仕組みについて話す
  • JavaScript のガベージコレクションメカニズムとメモリ管理
  • jsにおける新世代ガベージコレクションの知識ポイントまとめ

<<:  一般的なブラウザ互換性の問題(概要)

>>:  よくある MySQL テーブル設計エラーの概要

推薦する

Linux 上での Go 環境の構築のインストールと設定の説明

Linux で Go 環境を構築するのは非常に簡単です。 1. go1.2.1.linux-386....

H5ウェイクアップアプリの実装方法と注意点のまとめ

目次序文APPメソッドにジャンプURLスキームメタタグユニバーサルリンクさまざまな使い方URLスキー...

JS 手ぶれ補正機能の実装と使用シナリオ

目次1. 手ぶれ補正機能とは何ですか? 1. なぜ手ぶれ補正機能が必要なのでしょうか? 2. 手ぶれ...

jQueryはシンプルなボタンの色の変更を実装します

HTML と CSS で、ボタンの色を設定したいとします。 目的の効果は得られますが、プロセスはかな...

動的な背景グラデーション効果を実現するCSS3

CSS3 を学ぶということは、新しい機能と基本的な理論に慣れることを意味します。この記事では、ケー...

Centos7でファイルをバックアップするときは、バックアップファイルにバックアップの日付を追加します

Linux は、システム内のデバイス、インターフェース、ファイル、スタートアップ、アプリケーション ...

Dockerは単一のイメージを使用して複数のポートにマッピングします

必要:公式サイトのリソースサーバーは確かに1つのインスタンスでは使えず、複数のインスタンスを一緒に使...

VMware 仮想化 KVM のインストールと展開のチュートリアルの概要

仮想化1. 環境セントオス7.3 selinuxとファイアウォールを無効にする2. 仮想化環境の構成...

SpringBootをDockerにデプロイし、jarパッケージを置き換える方法の詳細な説明

目次プロジェクトディレクトリDockerファイルファイルの展開画像を生成するコンテナを起動するウェブ...

マウスオーバーボタンアニメーションを実現する純粋な CSS3 パート 2

前の 2 つの章を終えて、ボタンのフローティング アニメーションについて新たな理解が得られましたか?...

Apache Web サーバーを使用して 2 つ以上のサイトを構成する方法

人気があり強力な Apache Web サーバーで 2 つ以上のサイトをホストする方法。前回の記事で...

RGBカラーテーブルコレクション

RGBカラーテーブル色英語名RGB 16色雪255 250 250 #FFFAFAゴーストホワイト2...

CentOS 8 に MySql をインストールしてリモート接続を許可する方法

ダウンロードしてインストールします。まず、システムに MySQL または MariaDB があるかど...

高同時実行シナリオにおける nginx 最適化の詳細な説明

日常の運用・保守作業では、nginx サービスが頻繁に使用され、nginx の高同時実行性によって生...

MySQLでorder byを使用せずにランキングを実装する3つの方法のまとめ

ビジネスを想定: 2位の従業員の給与情報を見るデータベースを作成する emps が存在する場合はデー...