Java におけるガベージ コレクションとは何かを思い出してください。

ガベージ コレクションは、未使用のオブジェクトを破棄してランタイム メモリをすべて再利用するプロセスです。

場合によっては、プログラマが不要なオブジェクトを破棄するのを忘れ、それらに割り当てられたメモリが解放されないことがあります。ますます多くのシステム メモリが消費され、最終的にはそれ以上割り当てられなくなります。このようなアプリケーションは「メモリ リーク」の影響を受けます。

ある時点を過ぎると、新しいオブジェクトを作成するための十分なメモリがなくなり、プログラムはOutOfMemoryErrorにより異常終了します。

Java のガベージ コレクションは、Java プログラムがメモリを自動的に管理するプロセスです。Java プログラムは、Java 仮想マシン (JVM) 上で実行されるバイトコードにコンパイルされます。

Java プログラムが JVM 上で実行されると、オブジェクトがヒープ上に作成されます。ヒープとは、オブジェクトに割り当てられたメモリの一部です。

Java アプリケーションの実行中に、その中に新しいオブジェクトが作成されます。最終的には、一部のオブジェクトは不要になります。いつでも、ヒープ メモリは 2 種類のオブジェクトで構成されていると言えます。

  • ライブ- これらのオブジェクトは使用されており、他の場所から参照されています。
  • Dead - これらのオブジェクトは他では使用されておらず、参照もありません。

ガベージ コレクターは、これらの未使用のオブジェクトを見つけて削除し、メモリを解放します。

Java のガベージ コレクションは自動プロセスです。プログラマは、削除するオブジェクトを明示的にマークする必要はありません。

各 JVM は独自のバージョンのガベージ コレクションを実装できます。ただし、コレクターは、ヒープ メモリ内に存在するオブジェクトを処理して、到達不能なオブジェクトをマークまたは識別し、圧縮によってそれらを破棄するための標準 JVM 仕様に準拠する必要があります。

オブジェクトの到達可能性

オブジェクトが生きていると認識するには、リンクの存在だけでは十分ではありません。これは、一部の無効なオブジェクトが他の無効なオブジェクトを参照する可能性があるためです。そのため、オブジェクトへのすべての参照の中に、「ライブ」オブジェクトからの参照が少なくとも 1 つ存在する必要があります。

オブジェクトの到達可能性

ガベージ コレクターは、生きているオブジェクトと死んだオブジェクトを区別するために、 GC ルート (ガベージ コレクション ルート)の概念に従って動作します。100% ライブ オブジェクトがあり、そこから他のオブジェクトなどをアニメーション化するリンクがあります。

そのようなルートの例:

  • システム クラス ローダーによってロードされるクラス。
  • ライブストリーム。
  • 現在実行中のメソッドとローカル変数のパラメータ。
  • 同期のモニターとして使用されるオブジェクト。
  • 何らかの目的でガベージ コレクションから保持されるオブジェクト。
  • ガベージ コレクターは、これらのルートから開始して他のオブジェクトへの参照をたどって、メモリ内のオブジェクトのグラフ全体を調べます。

Java でのガベージ コレクションの手順

標準的なガベージ コレクションの実装には 3 つのステップがあります。

1. オブジェクトをライブとしてマークする

この時点で、ガベージ コレクター (GC) は、オブジェクト グラフを走査して、メモリ内のすべての生きているオブジェクトを識別する必要があります。

オブジェクトを訪問すると、そのオブジェクトが使用可能であるため、生きているとマークされます。GC ルートからアクセスできないすべてのオブジェクトは、ガベージ コレクションの候補とみなされます。

2. 死んだオブジェクトのクリーンアップ

マークアップ フェーズの後、メモリ空間は生きている (訪問された) オブジェクトまたは死んだ (訪問されていない) オブジェクトによって占有されます。クリーンアップ フェーズでは、これらの無効なオブジェクトを含むメモリ フラグメントが解放されます。

3. メモリ内に残ったオブジェクトをコンパクトに配置

前のフェーズで削除された死んだオブジェクトが隣り合う必要はありません。したがって、断片化された (半分空の) メモリ空間が得られる危険性があります。

しかし、もちろん、これを準備しておけば、ガベージ コレクターが無効なオブジェクトを削除する瞬間にメモリを圧縮することができます。残りはヒープの先頭の連続したブロックに配置されます。

圧縮プロセスにより、新しいオブジェクトにメモリを順次割り当てることが容易になります。