Java ガベージ コレクション メカニズムの深い理解

1. はじめに

Java ガベージ コレクション メカニズムは、Java 仮想マシン (JVM) のコア コンポーネントの 1 つであり、メモリ管理において重要な役割を果たします。アプリケーションで作成されたオブジェクトを自動的に追跡および管理でき、これらのオブジェクトが使用されなくなった場合、ガベージ コレクション メカニズムがそれらのオブジェクトが占有しているメモリを自動的に再利用し、メモリのこの部分を再利用できるようにします。この仕組みにより、開発者が手動でメモリを管理する負担が大幅に軽減され、不注意によるメモリリークを防ぐことができ、C++など他の言語に比べてJava言語の大きな利点となっています。

2、Java メモリ構造

Java メモリは主に次の 5 つの領域に分かれています。

  1. メソッド領域: 仮想マシンによってロードされたクラス情報、定数、静的変数などのデータを格納するために使用されます。
  2. ヒープ: Java ヒープは、JVM によって管理される最大のメモリ領域であり、ほとんどすべてのオブジェクト インスタンスと配列をヒープ上に割り当てる必要があります。また、メモリの割り当てとリサイクルを効率的に行うために、若い世代と古い世代の 2 つの部分に分割されています。
  3. 仮想マシン スタック (Java スタック) : 各スレッドにはプライベート スタックがあり、そのライフ サイクルはスレッドと同期されます。スタックフレームには、ローカル変数テーブル、オペランドスタック、ダイナミックリンク、メソッド出口などの情報が格納されます。
  4. ネイティブ メソッド スタック: ネイティブ メソッド スタックは、ネイティブ メソッドを提供する点を除いて、仮想マシン スタックと似ています。
  5. プログラム カウンター レジスタ: 現在のスレッドによって実行されるバイトコードの行番号インジケーターです。

このうち、メソッド領域とヒープは、Java ガベージ コレクターが焦点を当てる主な領域であり、次の説明の焦点でもあります。

3. ゴミとは何か

Java では、オブジェクトのライフサイクルは作成 (新規) から始まり、他のオブジェクトから参照されなくなったときに終了します。つまり、オブジェクトがそれを指す参照を持たない場合、そのオブジェクトはガベージとなり、ガベージ コレクターが再利用するのを待ちます。オブジェクトはまだスコープ内にある可能性がありますが、プログラムで再度使用することは不可能であり (たとえば、オブジェクトはローカル スコープでのみ使用されます)、この時点でもオブジェクトはガベージとみなされます。時間。ガベージ コレクターの主な仕事は、これらのガベージ オブジェクトを見つけて、それらが占有しているメモリを解放して、新しいオブジェクト用のスペースを提供することです。

4. ガベージコレクションアルゴリズム

1. マーク アンド スイープ アルゴリズム (マーク アンド スイープ)

これは最も基本的なガベージ コレクション アルゴリズムです。マーキングフェーズとクリアフェーズの 2 つのフェーズに分かれています。マーキング フェーズでは、すべてのオブジェクトを走査して、どのオブジェクトがまだ生きているかを確認します。クリーンアップ フェーズでは、マークされていないすべてのオブジェクトが削除されます。図に示すように:
ここに画像の説明を挿入

マーククリアのアルゴリズムは非常に直感的ですが、効率の問題、マークとクリアの 2 つのプロセスの効率が高くない、もう 1 つはスペースの問題、不連続なメモリの断片が多数発生してしまうという 2 つの問題があります。マーククリア後に生成されます。

2. コピーアルゴリズム(Copying)

効率の問題を解決するために、「コピー」アルゴリズムを採用できます。レプリケーション アルゴリズムは、利用可能なメモリを容量に応じて 2 つの同じサイズのブロックに分割し、一度にそのうちの 1 つだけを使用します。このメモリが使い果たされたら、残ったオブジェクトを別のメモリにコピーし、使用済みのメモリ領域を一度にクリーンアップします。この方法では、毎回 1 つのメモリが再利用されるため、メモリを割り当てるときにメモリの断片化やその他の問題を考慮する必要がありません。図に示すように:

ここに画像の説明を挿入
レプリケーション アルゴリズムは実装が簡単で、メモリ効率が高く、断片化が起こりにくいですが、最大の問題は、使用可能なメモリが元の半分に圧縮され、メモリが完全に利用されていないことです。また、生き残るオブジェクトの数が増加すると、レプリケーション アルゴリズムの効率が大幅に低下します。

3. マークとコンパクト

スペースの問題を解決するには、「マークソート」アルゴリズムを使用できます。マーキングプロセスは「マーククリア」アルゴリズムと同じですが、後続のステップではリサイクル可能なオブジェクトを直接クリーンアップするのではなく、生き残ったすべてのオブジェクトを一方の端に移動させてから、端の境界の外側のメモリを直接クリーンアップします。 。図に示すように:
ここに画像の説明を挿入

4. 世代別コレクション

現在の商用仮想マシンのガベージ コレクションは、「Generational Collection」アルゴリズムを採用しています。このアルゴリズムは、Java ヒープを新世代と旧世代に分割し、それぞれの時代の特性に応じて最適な収集アルゴリズムを採用することができます。オブジェクトの生存率が低い新世代では、コピーアルゴリズムを選択することができ、生き残ったオブジェクトの少額のコピーコストを支払うだけでコレクションを完了できます。古い世代では、オブジェクトの生存率が高く、オブジェクトに割り当てる追加のスペースがないため、ガベージ コレクションに「mark-clean」または「mark-compact」アルゴリズムを選択できます。

Java 自体は、これらのガベージ コレクション アルゴリズムを直接制御する API を提供しておらず、バックグラウンドで Java 仮想マシンによって自動的に実行されることに注意してください。ただし、これらの基本的なガベージ コレクション アルゴリズムを理解することは、より高度なガベージ コレクション技術 (並列コレクション、同時コレクション、増分コレクションなど) を理解するための基礎となります。

5. ガベージコレクター

Java HotSpot VM には数種類のガベージ コレクターが含まれており、それぞれに独自の特性があり、さまざまなシステムや使用シナリオに適しています。含む:

  • シリアル コレクター: ガベージの収集が完了するまで、他のすべてのワーカー スレッドを一時停止する必要があるシングル スレッドのコレクター。
  • パラレル コレクター: ガベージ コレクション中に収集が完了するまで他のすべてのワーカー スレッドを停止するマルチスレッド コレクター。
  • CMS (同時マーク スイープ) コレクター: 同時コレクター。その主な設計目標は、古い時代にガベージを収集する際の長期的な遅延を回避することです。
  • G1 (ガベージ ファースト) コレクター: サーバー側アプリケーション用のガベージ コレクターであり、予測可能な停止時間とガベージ コレクションの高スループットのニーズを満たすことができます。

各ガベージ コレクターには適用可能なシナリオがあり、良いものと悪いものの絶対的な区別はないことに注意してください。実際のシステム設計・開発では、アプリケーションの特性(システムの応答時間に対する要求が高いかどうかなど)やハードウェアリソースに応じて、最適なコレクタを選択する必要があります。

6. ガベージ コレクションをいつトリガーするか

Java では、ガベージ コレクションのタイミングは JVM によって決定されます。メソッドを呼び出して JVM にガベージ コレクションの実行を要求できますがSystem.gc()、これは単なる提案であり、JVM はこの要求を無視することもできます。

実際には、JVM は通常、次の状況でガベージ コレクションを実行します。

  • JVM のヒープ メモリ領域が不十分な場合、JVM はガベージ コレクションをトリガーして、使用されなくなったオブジェクトによって占有されているメモリを解放し、新しいオブジェクトに領域を割り当てます。
  • 旧世代 (Old Generation) スペースがいっぱいになると、フル GC がトリガーされ、GC が終了するまですべての Java アプリケーション スレッドが一時停止されます。
  • システムがアイドル状態の場合、JVM はシステムのメモリ使用効率を向上させるためにガベージ コレクションの実行を選択することもあります。

次の Java コードは、実行時にガベージ コレクションがどのように実行されるかを示します。

public class GCDemo {
    
    
    public static void main(String[] args) {
    
    
        Runtime runtime = Runtime.getRuntime();
        long before = runtime.freeMemory(); //获取开始时JVM空闲内存
        for (int i = 0; i < 1000000; i++) {
    
    
            String s = new String("Hello, World!");
            s = null; // 显式地断开s的引用,使得s所指向的对象可以被垃圾回收
        }
        long after = runtime.freeMemory(); //获取结束时JVM空闲内存
        System.out.println("Memory freed by GC: " + (before - after));
    }
}

このコードは、ガベージ コレクターによって解放されたメモリの量を出力します。ガベージ コレクションを明示的にトリガーしなかった場合でも、JVM が適切なタイミングでガベージ コレクションを実行することがわかります。

エピローグ

Java のガベージ コレクション メカニズムを理解し、習得することは、効率的で安定した Java プログラムを作成するために重要です。このブログでは、ガベージ コレクションのメカニズムの基本原理、JVM のメモリ構造、ガベージ コレクションのアルゴリズム、さまざまなガベージ コレクター、ガベージ コレクションのトリガー タイミングについて紹介しました。Java はメモリ管理の問題のほとんどをすでに処理していますが、Java 開発者として、より効率的なコードを記述し、メモリ リークなどの問題を回避するには、これらの基本概念を理解する必要があります。このブログがお役に立てば幸いです。ご質問がございましたら、メッセージを残してご相談ください。

おすすめ

転載: blog.csdn.net/weixin_46703995/article/details/131253783