Javaのスタックメモリとヒープスペース
1. 前書き
アプリケーションを最適な方法で実行するために、JVMはメモリをスタックメモリとヒープメモリに分割します。 Whenever we declare new variables and objects, call new method, declare a String or perform similar operations, JVM designates memory to these operations from either Stack Memory or Heap Space.
このチュートリアルでは、これらのメモリモデルについて説明します。 それらの主な違い、RAMへの保存方法、提供される機能、使用場所について説明します。
2. Javaのスタックメモリ
Stack Memory in Java is used for static memory allocation and the execution of a thread.メソッドに固有のプリミティブ値と、メソッドから参照されるヒープ内のオブジェクトへの参照が含まれます。
このメモリへのアクセスは、後入れ先出し(LIFO)順です。 新しいメソッドが呼び出されるたびに、スタックの最上部に新しいブロックが作成されます。このブロックには、プリミティブ変数やオブジェクトへの参照など、そのメソッドに固有の値が含まれます。
メソッドの実行が終了すると、対応するスタックフレームがフラッシュされ、フローは呼び出し元のメソッドに戻り、次のメソッドのためにスペースが使用可能になります。
2.1. スタックメモリの主な機能
これまでに説明したこととは別に、スタックメモリのその他の機能を次に示します。
-
新しいメソッドが呼び出されて返されるたびに拡大および縮小します
-
スタック内の変数は、それらを作成したメソッドが実行されている場合にのみ存在します
-
メソッドの実行が終了すると、自動的に割り当てと割り当て解除が行われます
-
このメモリがいっぱいの場合、Javaはjava.lang.StackOverFlowErrorをスローします
-
ヒープメモリと比較した場合、このメモリへのアクセスは高速です
-
各スレッドは独自のスタックで動作するため、このメモリはスレッドセーフです
3. Javaのヒープスペース
Heap space in Java is used for dynamic memory allocation for Java objects and JRE classes at the runtime。 新しいオブジェクトは常にヒープスペースに作成され、このオブジェクトへの参照はスタックメモリに保存されます。
これらのオブジェクトにはグローバルアクセスがあり、アプリケーションのどこからでもアクセスできます。
このメモリモデルは、世代と呼ばれる小さな部分にさらに分割されます。これらは次のとおりです。
-
Young Generation –これは、すべての新しいオブジェクトが割り当てられ、エージングされる場所です。 これがいっぱいになると、マイナーなガベージコレクションが発生します
-
Old or Tenured Generation –これは、長く存続するオブジェクトが格納される場所です。 オブジェクトが若い世代に保存されると、オブジェクトの年齢のしきい値が設定され、そのしきい値に達すると、オブジェクトは古い世代に移動されます
-
Permanent Generation –これは、ランタイムクラスとアプリケーションメソッドのJVMメタデータで構成されます
これらのさまざまな部分についても、この記事で説明しています–Difference Between JVM, JRE, and JDK.
要件に従って、ヒープメモリのサイズをいつでも操作できます。 詳細については、このlinked example articleにアクセスしてください。
3.1. Javaヒープメモリの主な機能
これまで説明してきたこととは別に、ヒープスペースのその他の機能を次に示します。
-
ヤングジェネレーション、オールドジェネレーションまたはテニュアジェネレーション、パーマネントジェネレーションなどの複雑なメモリ管理手法を介してアクセスされます
-
ヒープスペースがいっぱいの場合、Javaはjava.lang.OutOfMemoryErrorをスローします
-
このメモリへのアクセスは、スタックメモリよりも比較的遅い
-
このメモリは、スタックとは対照的に、自動的に割り当て解除されません。 メモリ使用量の効率を維持するために、ガベージコレクターが未使用のオブジェクトを解放する必要があります
-
スタックとは異なり、ヒープはスレッドセーフではなく、コードを適切に同期して保護する必要があります
4. 例
これまでに学んだことに基づいて、簡単なJavaコードを分析し、ここでメモリがどのように管理されているかを評価しましょう。
class Person {
int pid;
String name;
// constructor, setters/getters
}
public class Driver {
public static void main(String[] args) {
int id = 23;
String pName = "Jon";
Person p = null;
p = new Person(id, pName);
}
}
このステップバイステップで分析してみましょう:
-
main()メソッドに入ると、このメソッドのプリミティブと参照を格納するためのスペースがスタックメモリに作成されます。
-
整数idのプリミティブ値は、スタックメモリに直接格納されます
-
タイプPerson の参照変数p も、ヒープ内の実際のオブジェクトを指すスタックメモリに作成されます。
-
-
main()からパラメーター化されたコンストラクターPerson(int, String)を呼び出すと、前のスタックの上にさらにメモリが割り当てられます。 これは保存します:
-
スタックメモリ内の呼び出し元オブジェクトのthisオブジェクト参照
-
スタックメモリのプリミティブ値id
-
ヒープメモリ内の文字列プールからの実際の文字列を指すString引数personNameの参照変数
-
-
このデフォルトコンストラクタはさらにsetPersonName()メソッドを呼び出しており、そのために、前のメソッドの上にスタックメモリでさらに割り当てが行われます。 これにより、上記の方法で変数が保存されます。
-
ただし、新しく作成されたタイプPersonのオブジェクトp の場合、すべてのインスタンス変数はヒープメモリに保存されます。
この割り当てについては、次の図で説明しています。
5. 概要
この記事を締めくくる前に、スタックメモリとヒープスペースの違いを簡単に要約しましょう。
パラメータ | スタックメモリ | ヒープスペース |
---|---|---|
応用 |
スタックは、スレッドの実行中に一度に1つずつパーツで使用されます |
アプリケーション全体が実行時にヒープスペースを使用します |
Size |
スタックにはOSに応じたサイズ制限があり、通常はヒープよりも小さくなります |
ヒープにサイズ制限はありません |
ストレージ |
ヒープスペースで作成されたプリミティブ変数とオブジェクトへの参照のみを格納します |
新しく作成されたすべてのオブジェクトがここに保存されます |
注文 |
後入れ先出し(LIFO)メモリ割り当てシステムを使用してアクセスします |
このメモリには、若い世代、古い世代または古い世代、永続的な世代などの複雑なメモリ管理手法を介してアクセスします。 |
Life |
スタックメモリは、現在のメソッドが実行されている間のみ存在します |
アプリケーションが実行されている限り、ヒープスペースは存在します |
効率 |
ヒープと比較すると、割り当てが比較的高速です |
スタックと比較すると、割り当てが遅い |
Allocation/Deallocation |
このメモリは、メソッドが呼び出されて返されるときに、自動的に割り当ておよび割り当て解除されます。 |
ヒープスペースは、新しいオブジェクトが作成され、参照されなくなったときにGargabeCollectorによって割り当て解除されたときに割り当てられます。 |
6. 結論
スタックとヒープは、Javaがメモリを割り当てる2つの方法です。 この記事では、それらがどのように機能し、より良いJavaプログラムを開発するためにそれらをいつ使用するかを理解しました。
Javaでのメモリ管理の詳細については、this article hereを参照してください。 また、over in this articleについて簡単に説明するJVMガベージコレクタについても説明しました。