これから皆さんと共有しようとしているのは、GC アルゴリズムの最も基本的なアルゴリズムであるマーク/クリア アルゴリズムです。このアルゴリズムを理解できれば、次の 2 つは簡単です。
まず第一に、前の章で述べたルート検索アルゴリズムを思い出してください。このアルゴリズムはどのオブジェクトをリサイクルすべきかという問題を解決できますが、プログラム (プログラム) 内にあるため、ガベージ コレクションという重い責任を担うことはできません。 JVM 上で JAVA プログラムの実行中にガベージ コレクションを実行したい場合は、プログラムの実行に影響を与えることなくガベージを正常にリサイクルできるように、GC スレッドをプログラム内のスレッドと連携させる必要があります。プログラム。
この目的を達成するために、マーク/クリアアルゴリズムが登場しました。これが行うことは、ヒープ内の利用可能なメモリ領域が使い果たされると、プログラム全体を停止し (世界の停止とも呼ばれます)、次に 2 つのタスクを実行します。1 つ目はマーク付けで、2 つ目は項目がクリアされます。
以下の LZ では、マーキングとクリアが何を行うかについて詳しく説明します。
マーキング: マーキングのプロセスは、実際にはすべての GC ルートを走査し、GC ルートによって到達可能なすべてのオブジェクトを生きたオブジェクトとしてマークすることです。
クリア: クリア プロセスは、ヒープ内のすべてのオブジェクトをスキャンし、マークされていないすべてのオブジェクトをクリアします。
実際、これら 2 つの手順は特に複雑ではなく、理解するのが簡単です。 LZ は、プログラムの実行中に使用可能なメモリが使い果たされると、GC スレッドがトリガーされ、プログラムが一時停止され、残ったオブジェクトが再度マークされ、最後にすべてクリアされるというマーク/クリア アルゴリズムをわかりやすく説明します。ヒープ内のマークされていないオブジェクトを削除し、プログラムの実行を再開します。
以下に、LZ が上記のプロセスを説明するための一連の画像を作成しました。これらの画像と組み合わせて、このプロセスを直感的に見てみましょう。
この図は、プログラムの実行中のすべてのオブジェクトのステータスを表します。フラグ ビットはすべて 0 (つまり、マークされていません。以下のデフォルトは、マークされていない場合は 0、マークされている場合は 1 です)。このとき、メモリ容量がなくなると、JVM はアプリケーションを停止して GC スレッドを開始し、ルート検索アルゴリズムに従って、マーク後のオブジェクトのステータスは次のようになります。
ルート検索アルゴリズムに従って、ルート オブジェクトから到達可能なすべてのオブジェクトが生存オブジェクトとしてマークされることがわかります。この時点で、マーク付けの最初の段階が完了しています。次に、クリーンアップの第 2 段階が実行されます。クリーンアップが完了すると、残りのオブジェクトとそのステータスは次の図のようになります。
ご覧のとおり、マークされていないオブジェクトはリサイクルされてクリアされますが、マークされたオブジェクトは残り、マーク ビットは 0 にリセットされます。言うまでもなく、停止したプログラム スレッドを起動して、プログラムの実行を続行するだけです。
実際、このプロセスは複雑ではなく、非常に単純であるとさえ言えます。ただし、言及しておくべき点が 1 つあります。それは、なぜプログラムの実行を停止する必要があるのかということです。
これは実際には理解するのが難しいことではありません。プログラムと GC スレッドが一緒に実行されると仮定してみましょう。
図の一番右のオブジェクトをマークしたとします。とりあえずそれを A と呼びます。その結果、この時点でプログラム内で新しいオブジェクト B が作成され、A オブジェクトは B オブジェクトに到達できます。ただし、この時点では A オブジェクトがマークされているため、B オブジェクトのマーク ビットはマーキング段階を逃したため、この時点ではまだ 0 のままです。したがって、次のフェーズがクリアされるターンになると、新しいオブジェクト B はハードにクリアされます。その結果、GC スレッドによってプログラムが正常に動作しなくなることは想像に難くありません。
上記の結果は当然受け入れられません。新しいオブジェクトを作成したところ、GC 後に突然 null になりました。どうすればよいでしょうか。
ここまで、マーク/クリアアルゴリズム LZ の欠点を見てみましょう。アルゴリズムの原理を理解した後、その欠点を理解するのは簡単です。
1. まず第一に、その欠点は効率が比較的低く (再帰とヒープ オブジェクト全体のトラバーサル)、GC を実行するときにアプリケーションを停止する必要があるため、特に対話型のユーザー エクスペリエンスが非常に低下することです。まったく受け入れられないアプリケーションです。想像してみてください。Web サイトでプレイしていて、そのサイトが 1 時間に 5 分間ダウンした場合、それでもプレイしますか?
2. 2 番目の主な欠点は、この方法でクリアされた空きメモリが不連続であることです。これは、クリア後のメモリのレイアウトがメモリの隅々にランダムに表示されることです。当然乱雑になります。これに対処するために、JVM はメモリの空きリストを維持する必要があり、これもオーバーヘッドとなります。さらに、配列オブジェクトを割り当てる場合、連続したメモリ空間を見つけるのは困難になります。
その欠点を読んだ後、猿の友人の中には、「このアルゴリズムはまったく役に立たないのに、なぜ LZ はそのようなものを導入するのでしょうか?」と吐き出さずにはいられない人もいるかもしれません。
猿の友人、心配しないでください、アルゴリズム欠点がある場合、専門家は当然それを改善するために最善を尽くします。次に紹介する 2 つのアルゴリズムは、どちらもマーク/クリア アルゴリズムに基づいて最適化されています。次回はLZが具体的な内容をお伝えします。
これでこの共有は終わりです。0.0 を読んで何かを得ることができれば幸いです。
上記は、JVM メモリ管理の内容です --GC アルゴリズムの詳細な説明 (マーク/クリア アルゴリズムを完全に理解するには 5 分) 詳細については、PHP 中国語 Web サイト ( www.php.cn)!