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

スタックメモリとは何ですか? Java?
スタックメモリ Java スタックは、各スレッドのメソッドフレーム、ローカル変数、および参照変数を格納するJVMメモリ領域です。スタックへのアクセスは常に後入れ先出し(LIFO)順で行われるため、最後に呼び出されたメソッドが最上位に配置され、そのローカル変数はメソッドフレームとともにプッシュおよびポップされます。
各スレッド Java 仮想マシンは独自のスタックを受け取ります。このスタックは、メソッド呼び出しを分離し、スレッドセーフな状態に保つように設計されています。int、boolean、doubleなどのプリミティブなローカル変数はフレーム内に直接存在し、スタックに格納されるオブジェクト参照はヒープに割り当てられたオブジェクトを指します。
ヒープメモリとは何ですか? Java?
ヒープメモリは、すべての Java new演算子で作成されたオブジェクトと配列、およびそれらのオブジェクトに属する参照変数はインスタンスフィールドとして作成されます。スタックとは異なり、ヒープはすべてのスレッドで共有されるため、オブジェクトへのアクセスには同期が必要になることがよくあります。
ヒープは、ガベージコレクタが管理する領域です。最新のHotSpot JVMでは、ヒープは短命なオブジェクト用のヤング世代と長命なオブジェクト用のオールド世代に分割され、クラスのメタデータはメタスペースと呼ばれる別のネイティブ領域に格納されます。
メモリ割り当て Java
メモリ割り当て Java これは、JVMがプログラム実行中に変数、クラス、構造体のインスタンス用に仮想メモリ領域を確保するプロセスです。メモリは宣言時にオブジェクトに割り当てられるのではなく、参照のみが作成されます。実際のオブジェクト割り当てはnew演算子によって行われるため、すべてのオブジェクトはヒープ上に存在します。
その Java メモリ割り当ては、以下のセクションに分けられます。
- ヒープ
- スタック
- Code
- 静的
このメモリ分割は、ランタイムを効率的に管理するために必要である。
- その 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用のフレームが作成されます。
下の図に示すように、m1 内の変数 x は、スタック上の m1 のフレーム内にも作成されます。
メソッドm1はメソッドm2を呼び出します。スタック内では、m1のフレームの上にm2用の新しいフレームが作成されます。
ローカル変数bとcも、スタック上のm2のフレーム内で作成されます。
public void m2(int b){ boolean c; }
次に、m2はメソッドm3を呼び出します。ここでも、以下に示すように、スタックの最上部にm3用のフレームが作成されます。
ここで、メソッド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のオブジェクトを作成します。
参照変数refは、m3のフレーム内のスタック上に作成されます。
代入演算子は、参照変数をヒープ上のオブジェクトを指すようにします。
メソッドの実行が完了すると、制御は呼び出し元のメソッド(この場合はメソッドm2)に戻ります。
メソッドm3のフレームがスタックからフラッシュされます。
参照変数がヒープ上のオブジェクトを指しなくなったため、そのオブジェクトはガベージコレクションの対象となります。
メソッド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 ガベージコレクタは、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を代入することはできません。周囲のスタックフレームがポップされると、プリミティブ型の記憶領域は自動的に解放されます。


















