Javaのヒープスペースとスタック – Javaにおけるメモリ割り当て

以前、私はJavaのガベージコレクションとJavaの値渡しについての投稿をいくつか書きました。その後、Javaのヒープスペース、Javaのスタックメモリ、Javaでのメモリ割り当て、およびそれらの間の違いについて説明するための多くのメールを受け取りました。Javaの書籍やチュートリアルではヒープメモリとスタックメモリについての参照が多くありますが、プログラムの観点でのヒープメモリとスタックメモリの完全な説明はほとんどありません。

ジャバヒープスペース

JavaランタイムはJavaヒープスペースを使用してオブジェクトとJREクラスにメモリを割り当てます。オブジェクトを作成するときは常にヒープスペースで作成されます。ガベージコレクションはヒープメモリ上で実行され、参照がないオブジェクトによって使用されているメモリを解放します。ヒープスペースに作成されたオブジェクトはグローバルアクセスがあり、アプリケーションのどこからでも参照することができます。

Javaのスタックメモリ

Javaのスタックメモリはスレッドの実行に使用されます。その中には、一時的なメソッド固有の値やメソッドから参照されるヒープ内の他のオブジェクトへの参照が含まれます。スタックメモリは常にLIFO(後入れ先出し)の順序で参照されます。メソッドが呼び出されるたびに、メソッド内のローカルなプリミティブ値や他のオブジェクトへの参照を保持するための新しいブロックがスタックメモリに作成されます。メソッドが終了すると、そのブロックは使用されなくなり、次のメソッドで使用できるようになります。スタックメモリのサイズはヒープメモリと比較して非常に小さいです。

Javaプログラムにおけるヒープとスタックメモリ

シンプルなプログラムを使って、Heap(ヒープ)とStack(スタック)のメモリ使用を理解しましょう。

package com.scdev.test;

public class Memory {

	public static void main(String[] args) { // Line 1
		int i=1; // Line 2
		Object obj = new Object(); // Line 3
		Memory mem = new Memory(); // Line 4
		mem.foo(obj); // Line 5
	} // Line 9

	private void foo(Object param) { // Line 6
		String str = param.toString(); //// Line 7
		System.out.println(str);
	} // Line 8

}

下の画像は、上記のプログラムに関連してスタックとヒープメモリを示しており、それらがプリミティブなオブジェクトや参照変数を格納するためにどのように使用されているかを示しています。プログラムの実行手順を確認しましょう。

  • As soon as we run the program, it loads all the Runtime classes into the Heap space. When the main() method is found at line 1, Java Runtime creates stack memory to be used by main() method thread.
  • We are creating primitive local variable at line 2, so it’s created and stored in the stack memory of main() method.
  • Since we are creating an Object in the 3rd line, it’s created in heap memory and stack memory contains the reference for it. A similar process occurs when we create Memory object in the 4th line.
  • Now when we call the foo() method in the 5th line, a block in the top of the stack is created to be used by the foo() method. Since Java is pass-by-value, a new reference to Object is created in the foo() stack block in the 6th line.
  • A string is created in the 7th line, it goes in the String Pool in the heap space and a reference is created in the foo() stack space for it.
  • foo() method is terminated in the 8th line, at this time memory block allocated for foo() in stack becomes free.
  • In line 9, main() method terminates and the stack memory created for main() method is destroyed. Also, the program ends at this line, hence Java Runtime frees all the memory and ends the execution of the program.

Javaのヒープ領域(Heap Space)とスタックメモリ(Stack Memory)の違いは何ですか?

上記の説明に基づいて、HeapメモリとStackメモリの以下の違いを簡単に結論づけることができます。

    1. アプリケーションのすべての部分でヒープメモリが使用される一方、スタックメモリは実行スレッドのみで使用されます。

 

    1. オブジェクトが作成されると、常にヒープスペースに格納され、スタックメモリにはその参照が含まれます。スタックメモリには、ローカルの基本変数とヒープスペースのオブジェクトへの参照変数のみが含まれます。

 

    1. ヒープに格納されたオブジェクトはグローバルにアクセスできますが、スタックメモリは他のスレッドからアクセスできません。

 

    1. スタックのメモリ管理はLIFO方式で行われますが、ヒープメモリでは複雑です。ヒープメモリはYoung-Generation、Old-Generationなどに分割されています。詳細はJava Garbage Collectionを参照してください。

 

    1. スタックメモリは寿命が短く、ヒープメモリはアプリケーションの実行の最初から最後まで存続します。

 

    1. 起動サイズとヒープメモリの最大サイズを定義するために-Xmsと-Xmx JVMオプションを使用できます。スタックメモリのサイズを定義するためには、-Xssを使用できます。

 

    1. スタックメモリがいっぱいの場合、Javaランタイムは java.lang.StackOverflowError をスローしますが、ヒープメモリがいっぱいの場合は java.lang.OutOfMemoryError: Java Heap Space エラーがスローされます。

 

    スタックメモリのサイズはヒープメモリに比べて非常に少ないです。メモリ割り当て(LIFO)の単純さにより、スタックメモリはヒープメモリに比べて非常に高速です。

それがJavaアプリケーションにおけるJava Heap SpaceとStack Memoryに関するすべてです。任意のJavaプログラムが実行される際のメモリ割り当てに関する疑問が解消されることを願っています。

参照:https://en.wikipedia.org/wiki/Java_memory_model

Javaメモリモデルについて説明されているリンクはこちらです。

コメントを残す 0

Your email address will not be published. Required fields are marked *