(1) ガベージコレクターの基本的な前提
(1) 最近メモリ空間を割り当てられたオブジェクトは、解放する必要がある可能性が高くなります。通常、メソッドを実行する前に、そのメソッドで使用されるオブジェクトにメモリ領域を割り当てる必要があります。最近割り当てられたオブジェクトのコレクションを検索すると、最小限の作業でできるだけ多くの空きメモリ領域を解放できます。
(2) ライフタイムが最も長いオブジェクトは、解放する必要がある可能性が最も低くなります。数ラウンドのガベージ コレクション後にまだ存在するオブジェクトは、次のラウンドのガベージ コレクションで解放できる一時オブジェクトである可能性は低く、多くの場合、これらのメモリ ブロックの検索には多大な作業が必要ですが、解放できるのはメモリ領域のほんの一部だけです。リリースされました。
(3) 同時にメモリが割り当てられたオブジェクトは、通常、同時に使用されます。同時にメモリを割り当てるオブジェクト ストレージの場所を相互に接続すると、キャッシュのパフォーマンスを向上させることができます。
(2) いくつかのガベージコレクションメカニズム
(1) マークスイープコレクター
この種のコレクターは、最初にオブジェクトグラフを走査して到達可能なオブジェクトにマークを付け、次にスタックをスキャンしてマーク解除を見つけますオブジェクトを作成し、その記憶を解放します。このタイプのコレクターは通常、単一のスレッドを使用して動作し、他の操作を停止します。
(2) マーク-コンパクト コレクター
マーク-スイープ-コンパクト コレクターとも呼ばれ、マーク-スイープ コレクターと同じマーキング フェーズを持ちます。第 2 フェーズでは、スタックを圧縮するために、マークされたオブジェクトがスタックの新しい領域にコピーされます。このコレクターは他の操作も停止します。
(3) コピーコレクター
このコレクターは、スタックを 2 つのドメイン (しばしばハーフスペースと呼ばれます) に分割します。毎回スペースの半分だけが使用され、jvm によって生成された新しいオブジェクトはスペースの残りの半分に配置されます。 gc が実行されると、到達可能なオブジェクトがスペースの残りの半分にコピーされ、スタックが圧縮されます。この方法は、存続期間の短いオブジェクトに適しています。存続期間の長いオブジェクトを継続的にコピーすると、効率が低下します。
(4) インクリメンタルコレクター
インクリメンタルコレクターはスタックを複数のドメインに分割し、一度に 1 つのドメインからのみガベージを収集します。これにより、アプリケーションに軽度の中断が発生します。
(5) 世代別コレクター
このコレクターは、スタックを 2 つ以上のドメインに分割して、異なるライフタイムを持つオブジェクトを格納します。 jvm によって生成された新しいオブジェクトは、通常、フィールドの 1 つに配置されます。時間が経つにつれて、生き残ったオブジェクトは耐用年数を獲得し、より長く存続するドメインに転送されます。世代別コレクターは、ドメインごとに異なるアルゴリズムを使用してパフォーマンスを最適化します。
(6) コンカレントコレクター
コンカレントコレクターはアプリケーションと同時に実行されます。これらのコレクターは通常、特定のタスクを完了するために、ある時点で他の操作 (圧縮など) を停止する必要がありますが、他のアプリケーションは他のバックグラウンド操作を実行できるため、他の処理を中断する実際の時間は大幅に短縮されます。
(7) 並列コレクター
並列コレクターは、いくつかの従来のアルゴリズムを使用し、複数のスレッドを使用して作業を並行して実行します。マルチ CPU マシンでマルチスレッド テクノロジを使用すると、Java アプリケーションのスケーラビリティを大幅に向上させることができます。
(3) .NET Framework のガベージ コレクション メカニズム
.NET Framework にはマネージド ヒープが含まれており、すべての .NET 言語が参照型オブジェクトを割り当てるときに使用します。値型のような軽量オブジェクトは常にスタック上に割り当てられますが、すべてのクラス インスタンスと配列はマネージド ヒープであるメモリ プールに生成されます。
.NET Framework のガベージ コレクターは世代別ガベージ コレクター (Generational Garbage Collector) と呼ばれます。これは、割り当てられたオブジェクトが 3 つのカテゴリ、つまり「世代」に分割されることを意味します。それぞれ 0、1、2 です。世代 0、1、2 に対応するマネージド ヒープの初期サイズは、それぞれ 256K、2M、10M です。ガベージ コレクターは、サイズを変更することでパフォーマンスが向上すると判断した場合、マネージド ヒープのサイズを変更します。たとえば、アプリケーションが多くの小さなオブジェクトを初期化し、これらのオブジェクトがすぐにリサイクルされる場合、ガベージ コレクターは世代 0 のマネージド ヒープを 128K に増やし、リサイクルの頻度を増やします。状況が逆転し、ガベージ コレクターが世代 0 のマネージド ヒープ内の多くの領域を再利用できないと判断した場合、マネージド ヒープ サイズが増加します。アプリケーションが初期化されるまで、マネージド ヒープのすべてのレベルは空です。オブジェクトが初期化されると、オブジェクトは初期化された順序でマネージド ヒープの世代 0 に配置されます。
最近メモリ空間が割り当てられたオブジェクトは世代 0 に配置されます。世代 0 はプロセッサの 2 番目のレベル (L2) キャッシュに収まるほど小さいため、世代 0 はその中のオブジェクトへの高速アクセスを提供します。アクセス。ガベージ コレクションのラウンドの後、まだ世代 0 にあるオブジェクトは世代 1 に移動されます。別のラウンドのガベージ コレクションの後、まだ世代 1 にあるオブジェクトは世代 2 に移動されます。世代 2 には、少なくとも 2 ラウンドの収集を経た長命オブジェクトが含まれています。
C# プログラムがオブジェクトにメモリを割り当てると、マネージド ヒープは新しいオブジェクトに必要なメモリをほぼ即座に返すことができます。マネージド ヒープがこれほど効率的なメモリ割り当てパフォーマンスを実現できる理由は、次のより単純なデータ構造によるものです。マネージド ヒープ。マネージド ヒープは単純なバイト配列に似ており、最初に利用可能なメモリ空間へのポインタを持ちます。
オブジェクトによってブロックが要求されると、上記のポインター値が呼び出し元の関数に返され、ポインターは次に利用可能なメモリ空間を指すように再調整されます。マネージド メモリのブロックの割り当ては、ポインタの値をインクリメントするよりもわずかに複雑なだけです。これもマネージド ヒープのパフォーマンス最適化の 1 つです。ガベージ コレクションをあまり必要としないアプリケーションでは、マネージド ヒープは従来のヒープよりも優れたパフォーマンスを発揮します。
この線形メモリ割り当て方法により、C# アプリケーションで同時に割り当てられるオブジェクトは、通常、マネージド ヒープ上で互いに隣接して割り当てられます。この配置は、メモリ ブロック サイズに基づく従来のヒープ メモリ割り当てとはまったく異なります。たとえば、同時に割り当てられた 2 つのオブジェクトがヒープ上で遠く離れて配置され、キャッシュのパフォーマンスが低下する可能性があります。したがって、メモリ割り当ては高速ですが、一部のより重要なプログラムでは、世代 0 で使用可能なメモリが完全に消費される可能性があります。世代 0 は L2 バッファに収まるほど小さいため、未使用のメモリは自動的に解放されないことに注意してください。世代 0 に割り当てられる有効なメモリがない場合、世代 0 でガベージ コレクションのラウンドがトリガーされます。このラウンドのガベージ コレクションでは、参照されなくなったすべてのオブジェクトが削除され、現在使用中のオブジェクトは削除されます。世代 1 に移動されました。ジェネレーション 0 ガベージ コレクションは最も一般的なタイプのコレクションで、非常に高速です。第 0 世代のガベージ メモリ コレクションが十分なメモリを効果的に要求できない場合、第 1 世代のガベージ メモリ コレクションが開始されます。ジェネレーション 2 ガベージ コレクションは、ジェネレーション 1 およびジェネレーション 0 ガベージ コレクションで十分なメモリを提供できない場合に限り、最後の手段として使用する必要があります。各世代のガベージ コレクション後に使用可能なメモリがまだない場合は、OutOfMemeryException がスローされます。
(4) Javaのガベージコレクションの仕組み
Javaプログラムを実行する際、メモリはどのように配置されるのでしょうか? 『Java プログラミング思考』では 6 つの場所が言及されています:
(1) Register (登録)
(2) Stack (スタック)
(3) Heap: used すべての Java オブジェクトを配置します
(4) 静的記憶領域 (静的ストレージ): 「プログラム実行中」常に存在するデータを保存するために使用されます。 statci で変更されました。
(5) 定常記憶領域
(6) 非RAM記憶領域:ディスク記憶領域、つまり非メモリ領域と理解しています。
Sun HotSpot 1.4.1 は、ヒープを 3 つの主要なドメイン (新しいドメイン、古いドメイン、永続ドメイン) に分割する世代別コレクターを使用します。 Jvm によって生成されたすべての新しいオブジェクトは、新しいドメインに配置されます。オブジェクトは一定回数のガベージ コレクション サイクルを通過すると、その有効期間を取得し、古いドメインに入ります。永続ドメインでは、jvm はクラスとメソッドのオブジェクトを保存します。構成の目的上、永続ドメインは別個のドメインであり、ヒープの一部とはみなされません。この観点から、HotSpot エンジン テクノロジを使用する JVM は、.NET Framework と同様のガベージ コレクション メカニズム、つまり世代別ガベージ コレクション方式を採用する必要があります。
これらのドメインのサイズを制御する方法は次のとおりです。 -Xms および -Xmx を使用して、ヒープ全体の元のサイズまたは最大サイズを制御できます。
次のコマンドは、初期サイズを 128M に設定します:
java –Xms128m
–Xmx256m 新しいドメインのサイズを制御するには、-XX:NewRatio を使用して、新しいドメイン。
次のコマンドはヒープ全体を128mに設定し、新しいドメインの比率を3に設定します。つまり、新しいドメインと古いドメインの比率は1:3、新しいドメインは1/4です。ヒープまたは 32M:
java – Xms128m –Xmx128m
–XX:NewRatio =3 は、-XX:NewSize と -XX:MaxNewsize を使用して、新しいドメインの初期値と最大値を設定できます。
次のコマンドは、新しいドメインの初期値と最大値を 64m に設定します:
java –Xms256m –Xmx256m –Xmn64m
永続ドメインのデフォルトのサイズは 4m です。プログラムを実行するとき、jvm はニーズに合わせて永続ドメインのサイズを調整します。調整するたびに、JVM はヒープ上で完全なガベージ コレクションを実行します。
永続的なドメインのサイズを増やすには、-XX:MaxPerSize フラグを使用します。 WebLogic Server アプリケーションがより多くのクラスをロードする場合、多くの場合、永続ドメインの最大サイズを増やすことが必要になります。 jvm がクラスをロードすると、永続ドメイン内のオブジェクトが大幅に増加するため、jvm は永続ドメインのサイズを継続的に調整します。調整を避けるには、-XX:PerSize フラグを使用して初期値を設定します。
次に、永続ドメインの初期値を32m、最大値を64mに設定します。
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
デフォルトでは、HotSpot は新しいドメインでレプリケーション コレクターを使用します。ドメインは通常 3 つの部分に分かれています。最初の部分は Eden で、新しいオブジェクトを生成するために使用されます。他の 2 つの部分はレスキュー スペースと呼ばれ、Eden がいっぱいになると、コレクターはアプリケーションを停止し、現在のレスキュー スペースから到達可能なオブジェクトを現在のレスキュー スペースにコピーします。レスキュースペース。救助スペースからの役割と救助スペースへの役割を交換します。存続しているオブジェクトは、有効期限が切れて古いドメインに転送されるまで、サルベージ スペースにレプリケートされます。 -XX:SurvivorRatio を使用して、新しいドメイン サブスペースのサイズを制御します。
NewRationと同様に、SurvivorRationは、エデン空間に対する特定のレスキュードメインの比率を指定します。たとえば、次のコマンドは、新しいドメインを 64m に設定し、Eden が 32m を占有し、各レスキュー ドメインが 16m を占有します。デフォルト この状態では、HotSpot は新しいドメインにコピー コレクターを使用し、古いドメインにマーク スイープ コンパクト コレクターを使用します。アプリケーションによって生成されるオブジェクトのほとんどは有効期間が短いため、新しいドメインでコピー コレクターを使用することは非常に意味があります。理想的には、すべての遷移オブジェクトは、エデン空間の外に移動されるときに収集されます。これが可能で、エデン空間から移動されたオブジェクトが長命である場合、理論的には、レスキュー空間で繰り返しコピーされることを避けるために、それらをすぐに古い空間に移動することができます。ただし、アプリケーションには中程度から長期間存続するオブジェクトの割合が少ないため、この理想的な状態に適合することはできません。古いドメインを圧縮するよりもオブジェクトの小さな部分をコピーする方がコストがかからないため、これらの中程度から長期間存続するオブジェクトは新しいドメインに保持することをお勧めします。新しいドメインでのオブジェクトのコピーを制御するには、-XX:TargetSurvivorRatio を使用してレスキュー スペースの比率を制御します (この値はレスキュー スペースの使用率を設定します。たとえば、レスキュー スペース ビットは1M、値 50 は 500K が使用可能であることを意味します)。値はパーセントであり、デフォルト値は 50 です。大きなスタックで低い sruvivorratio が使用される場合は、ベイルアウト スペースをより有効に活用するために、この値を 80 ~ 90 に増やす必要があります。上限を制御するには、-XX:maxtenuring しきい値を使用します。
すべてのレプリケーションが確実に行われ、オブジェクトが eden から古いドメインに拡張されるようにするには、MaxTenuring Threshold を 0 に設定します。設定が完了すると、実際にはレスキュー空間は使用されなくなるため、Eden 空間を最大化するために SurvivorRatio を最大値に設定する必要があります。設定は次のとおりです:
java … -XX:MaxTenuringThreshold=0 – XX:SurvivorRatio=50000 …
追記:
「Java 仮想マシンの 10 年」でも述べたように、「過去 5 年間は最適化 (JVM) を継続した 5 年間でした。最適化を継続するにはいくつかの方法があります」 1 つ目は、新しいサンプリング アルゴリズムを研究することです。サンプリングはさまざまな最適化戦略に関連するため、2 つ目は、プログラム全体のパフォーマンスに大きな影響を与えるガベージ コレクションの方法を研究することです。短い一時停止はユーザー エクスペリエンスに悪影響を及ぼします。そのため、ガベージ コレクションの効率を向上させて遅延を減らす方法として、プログレッシブ コレクション、トレイン アルゴリズムなどのさまざまなアルゴリズムが登場しました。「言語の実行速度と効率を向上させる」というものです。デザイン開発者は常に目標を追求するため、ガベージ コレクション アルゴリズムも時間の経過とともに開発されます。 C# や Java のガベージ コレクション メカニズムについて話してほしいとあえて頼む面接官はいないと思います (少なくとも私はまだそれに遭遇したことがありません)。一度議論を深めれば、多くの問題で記事を書くのに十分です。長い本。しかし、孔子が東の山に登って小さな魯になり、泰山に登って小さな世界になった、深く探究してその起源をたどることは本当に美しいことです。上記は Java と C# のガベージ コレクション メカニズムの詳細な紹介です。さらに関連するコンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目してください。