メモリ管理 Java

⚡ スマートサマリー

メモリ管理 Java JVM が実行時メモリをスタック、ヒープ、 Code静的領域、メソッド呼び出し中にオブジェクト参照がどのように流れるか、そしてガベージコレクタが到達不能なオブジェクトをどのように回収してアプリケーションを安定させ、メモリリークを防ぐか。

  • 🧠 JVMメモリレイアウト: Java メモリは、オブジェクト用のヒープ、メソッドフレームとローカル変数用のスタック、さらにバイトコードと静的データ用の専用領域に分割されます。
  • 📚 スタックとヒープ: スタックフレームは後入れ先出し(LIFO)の順序に従い、プリミティブ型と参照型を格納します。一方、ヒープはnew演算子で作成されたすべてのオブジェクトを保持します。
  • ♻️ ガベージコレクション: ガベージコレクター trac参照チェーンを介してksの到達可能性を確保し、どのスレッドも到達できないオブジェクトからメモリを自動的に解放します。
  • 現代のコレクター: 本番環境のワークロードでは、マルチギガバイトのヒープ全体にわたる低遅延のガベージコレクションを実現するために、G1、ZGC、およびShenandoahへの依存度が高まっている。
  • 🧪 実践例: Student クラスのステップバイステップの解説では、参照がいつガベージコレクションの対象となるか、そして参照を null にすることで基となるオブジェクトが解放される方法を示します。

メモリ管理 Java

スタックメモリとは何ですか? Java?

スタックメモリ Java スタックは、各スレッドのメソッドフレーム、ローカル変数、および参照変数を格納するJVMメモリ領域です。スタックへのアクセスは常に後入れ先出し(LIFO)順で行われるため、最後に呼び出されたメソッドが最上位に配置され、そのローカル変数はメソッドフレームとともにプッシュおよびポップされます。

各スレッド Java 仮想マシンは独自のスタックを受け取ります。このスタックは、メソッド呼び出しを分離し、スレッドセーフな状態に保つように設計されています。int、boolean、doubleなどのプリミティブなローカル変数はフレーム内に直接存在し、スタックに格納されるオブジェクト参照はヒープに割り当てられたオブジェクトを指します。

ヒープメモリとは何ですか? Java?

ヒープメモリは、すべての Java new演算子で作成されたオブジェクトと配列、およびそれらのオブジェクトに属する参照変数はインスタンスフィールドとして作成されます。スタックとは異なり、ヒープはすべてのスレッドで共有されるため、オブジェクトへのアクセスには同期が必要になることがよくあります。

ヒープは、ガベージコレクタが管理する領域です。最新のHotSpot JVMでは、ヒープは短命なオブジェクト用のヤング世代と長命なオブジェクト用のオールド世代に分割され、クラスのメタデータはメタスペースと呼ばれる別のネイティブ領域に格納されます。

メモリ割り当て Java

メモリ割り当て Java これは、JVMがプログラム実行中に変数、クラス、構造体のインスタンス用に仮想メモリ領域を確保するプロセスです。メモリは宣言時にオブジェクトに割り当てられるのではなく、参照のみが作成されます。実際のオブジェクト割り当てはnew演算子によって行われるため、すべてのオブジェクトはヒープ上に存在します。

その Java メモリ割り当ては、以下のセクションに分けられます。

  1. ヒープ
  2. スタック
  3. Code
  4. 静的

このメモリ分割は、ランタイムを効率的に管理するために必要である。

  • その Code このセクションにはコンパイルされた バイトコード.
  • その スタック セクションストア メソッド、ローカル変数、および参照変数.
  • その ヒープ セクションに含まれるもの オブジェクト また、インスタンスフィールドとして保持される参照変数を含む場合もあります。
  • その 静的 セクションは 静的データと静的メソッド すべてのインスタンスで共有されます。

ローカル変数とインスタンス変数の違い

JVM 内の各種類の変数がどこに存在するかを理解することは、スタックとヒープの動作を説明するのに役立ちます。 インスタンス変数 宣言されています クラス内だがメソッド外そしてそれは、そのオブジェクトの一部としてヒープ上に存在します。

class Student{ 
int num; // num is instance variable 
public void showData{}

A ローカル変数 宣言されています メソッド内部(メソッド引数を含む)、アクティブフレーム内のスタック上に存在する。

public void sum(int a){

int x = a + 3;

// a, x are local variables

}

スタックとヒープの違い

スタックとヒープは、JVM内部で異なる問題を解決します。スタックは、メソッドスコープに関連付けられた短命データに対して、各スレッドに高速かつ決定論的なメモリ割り当てを提供します。一方、ヒープは、どのスレッドも参照できる長命オブジェクトのための共有領域を提供します。以下の短いビデオでは、この違いを簡潔にまとめ、その後の解説に進みましょう。

詳しくはこちら こちら ビデオにアクセスできない場合

StackとHeapがどのように連携するかを見るために、メソッドm1を呼び出すmainメソッドを考えてみましょう。

public void m1{
int x = 20;
}

JVMスタック内で、メソッドm1用のフレームが作成されます。

Java スタックとヒープ

下の図に示すように、m1 内の変数 x は、スタック上の m1 のフレーム内にも作成されます。

Java スタックとヒープ

メソッドm1はメソッドm2を呼び出します。スタック内では、m1のフレームの上にm2用の新しいフレームが作成されます。

Java スタックとヒープ

Java スタックとヒープ

ローカル変数bとcも、スタック上のm2のフレーム内で作成されます。

public void m2(int b){
boolean c;
}

次に、m2はメソッドm3を呼び出します。ここでも、以下に示すように、スタックの最上部にm3用のフレームが作成されます。

Java スタックとヒープ

Java スタックとヒープ

ここで、メソッドm3がAccountクラスのオブジェクトを作成するとします。 インスタンス変数 int p と int q。

class Account {
    int p;
    int q;
}

以下はメソッドm3のコードです。

public void m3(){
    Account ref = new Account();
    // more code
}

`new Account()`という文は、ヒープ上にAccountのオブジェクトを作成します。

Java スタックとヒープ

参照変数refは、m3のフレーム内のスタック上に作成されます。

Java スタックとヒープ

代入演算子は、参照変数をヒープ上のオブジェクトを指すようにします。

Java スタックとヒープ

メソッドの実行が完了すると、制御は呼び出し元のメソッド(この場合はメソッドm2)に戻ります。

Java スタックとヒープ

メソッドm3のフレームがスタックからフラッシュされます。

Java スタックとヒープ

参照変数がヒープ上のオブジェクトを指しなくなったため、そのオブジェクトはガベージコレクションの対象となります。

Java スタックとヒープ

メソッドm2の処理が完了すると、スタックからポップされ、その中のすべての変数が使用できなくなります。メソッドm1についても同様の処理が行われ、最終的に制御はメインメソッドに戻ります。

オブジェクトがインスタンス変数として別のオブジェクトへの参照を保持している場合はどうなるでしょうか?

public static void main(String args[]) {
    A parent = new A();
    // more code
}
class A {
    B child = new B();
    int e;
}
class B {
    int c;
    int d;
}

この場合、参照変数 child は A オブジェクトの一部としてヒープ上に存在し、以下に示すように、それ自身の B オブジェクトを指し示します。

Java スタックとヒープ

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

ガベージコレクション Java ガベージコレクタは、JVMが自動的にメモリ管理を実行するプロセスです。ガベージコレクタは、どの有効な参照からもアクセスできなくなったオブジェクトを検出し、そのメモリを解放します。動的メモリ割り当てはnew演算子によって行われ、プログラムがそのオブジェクトへの参照を保持しなくなるまで、メモリは割り当てられたままになります。

参照がなくなると、オブジェクトは不要とみなされ、占有していたメモリを解放できます。オブジェクトを明示的に破棄する必要はありません。 Java ガベージコレクターによって自動的に解放処理が行われます。

この背後にある技術は、 ガベージコレクションメモリを解放できないプログラムは、割り当てるものがなくなると最終的にクラッシュします。このようなプログラムは、 メモリリーク. ガベージコレクション Java 自動的に実行されます プログラムのライフサイクル全体を通して、手動による割り当て解除の負担が軽減され、情報漏洩のリスクも低減されます。

一方、C言語では、プログラマーはfree()関数を通して動的に割り当てられたメモリを解放する責任を負います。 Java メモリ管理は大きな利点となる。

最新の HotSpot JVM には、さまざまなワークロードに合わせて調整された複数のガベージ コレクターが付属しています。デフォルトの G1 ガベージ コレクターは、マルチギガバイトのヒープでバランスの取れたスループットと一時停止時間を目標としています。ZGC と Shenandoah は、非常に大きなヒープでミリ秒未満の一時停止を目指しており、tracレイテンシーに敏感なサービスに適しています。適切なコレクターを選択し、ヤング世代、オールド世代、メタスペースのサイズを調整することは、コアスキルです。 Java パフォーマンス作品。

注意: すべてのオブジェクトは、メモリのヒープ領域に作成されます。ヒープ領域は、ガベージコレクタが管理する領域です。

例: ガベージコレクタの仕組みを学ぶ Java

このチュートリアルでは、シンプルなプログラム内で参照がガベージコレクションの対象となるタイミングを示します。

ステップ1) 次のコードをエディターにコピーします。

class Student{
int a;
int b;
  public void setData(int c,int d){
    a=c;
    b=d;
  }
  public void showData(){
    System.out.println("Value of a = "+a);
    System.out.println("Value of b = "+b);
  }
  public static void main(String args[]){
    Student s1 = new Student();
    Student s2 = new Student();
    s1.setData(1,2);
    s2.setData(3,4);
    s1.showData();
    s2.showData();
    //Student s3;
    //s3=s2;
    //s3.showData();
    //s2=null;
    //s3.showData();
    //s3=null;
    //s3.showData();
  }
}

ステップ2) コードを保存、コンパイル、実行します。図に示すように、2つのオブジェクトと2つの参照変数が作成されます。

 ガベージコレクターの仕組み

ステップ3) 20行目、21行目、22行目のコメントを解除してください。コードを保存、コンパイル、実行してください。

ステップ4) 下の図に示すように、2つの参照変数が同じオブジェクトを指すようになりました。

ガベージコレクターの仕組み

ステップ5) 23行目と24行目のコメントを解除してください。コードを保存、コンパイル、実行してください。

ステップ6) 以下に示すように、s2 は null になりますが、s3 はまだオブジェクトを指しているため、オブジェクトはまだガベージ コレクションの対象になりません。

 ガベージコレクターの仕組み

ステップ7) 25行目と26行目のコメントを解除してください。コードを保存、コンパイル、実行してください。

ステップ8) この時点では、そのオブジェクトへの参照は存在しないため、ガベージコレクションの対象となります。ガベージコレクタはメモリからそのオブジェクトを削除し、復元する方法はありません。

 ガベージコレクターを学ぶ

オブジェクトを削除する方法 Java?

Java には手動削除演算子が用意されていないため、標準的なアプローチは、ガベージコレクタがオブジェクトを回収できるように、オブジェクトへのすべての参照を削除することです。

1) オブジェクトをガベージコレクションの対象にするには、そのオブジェクトを指すすべての参照変数を null に代入します。

2) プリミティブ型はオブジェクトではないため、nullを代入することはできません。周囲のスタックフレームがポップされると、プリミティブ型の記憶領域は自動的に解放されます。

オブジェクトを削除する方法 Java

よくあるご質問

スタックには、メソッドフレーム、ローカル変数、および参照がスレッドごとに後入れ先出し(LIFO)の順序で格納されます。ヒープには、new演算子で作成されたすべてのオブジェクトが格納され、スレッド間で共有されるため、ガベージコレクタによって管理されます。

ガベージコレクタは、アクティブなスレッドや静的フィールドなどのGCルートから参照チェーンをたどります。ルートから到達できないオブジェクトは到達不能とみなされ、次のガベージコレクションサイクルで解放の対象となります。

ヤング世代は、エデンとサバイバー空間に短命なオブジェクトを保持します。オールド世代は、複数のコレクションを生き残るオブジェクトを保持します。メタスペースは、クラスメタデータを格納するネイティブメモリ領域であり、以前のPermGenを置き換えました。 Java 8.

G1 はデフォルトであり、マルチギガバイトのヒープ上のほとんどのワークロードに適しています。ZGC と Shenandoah は非常に大きなヒープでミリ秒未満の一時停止を目標としており、レイテンシに敏感なサービスを実行するのに適しています。 Java 17以降。

オブジェクトを指すすべての参照をnullに設定するか、スタックフレームがポップされたときに参照がスコープ外になるようにします。オブジェクトへの有効な参照がなくなると、ガベージコレクターはヒープメモリを解放します。

はい。AIを活用したチューニングツールは、GCログ、割り当て率、一時停止ヒストグラムを分析し、ヒープサイズ、コレクタフラグ、ヤング世代比率を推奨します。特にG1、ZGC、Shenandoahワークロードにおいては、手動チューニングと比較してフィードバックループを短縮できます。

AIベースのオブザーバビリティプラットフォームは、ヒープダンプとライブメトリクスを取り込み、保持されたオブジェクトグラフをクラスタリングして、疑わしいクラスと参照チェーンを特定します。これにより、手動のヒープ分析よりも迅速にメモリリーク候補が明らかになり、本番環境での根本原因の特定に役立ちます。