웹사이트 검색

Java 힙 공간과 스택 - Java의 메모리 할당


예전에 저는 Java is Pass by Value에 대한 몇 개의 게시물을 썼습니다. 그 후 Java 힙 공간, Java 스택 메모리, Java의 메모리 할당 및 이들 간의 차이점에 대해 설명하는 많은 이메일을 받았습니다. Java, Java EE 서적 및 자습서에서 힙 및 스택 메모리에 대한 많은 참조를 볼 수 있지만 프로그램 측면에서 힙 및 스택 메모리가 무엇인지에 대한 완전한 설명은 거의 없습니다.

Java 힙 공간

Java 힙 공간은 Java 런타임에서 객체 및 JRE 클래스에 메모리를 할당하는 데 사용됩니다. 객체를 생성할 때마다 항상 힙 공간에 생성됩니다. 가비지 수집은 힙 메모리에서 실행되어 참조가 없는 객체가 사용하는 메모리를 해제합니다. 힙 공간에 생성된 모든 개체는 전역 액세스 권한이 있으며 응용 프로그램 어디에서나 참조할 수 있습니다.

자바 스택 메모리

Java 스택 메모리는 스레드 실행에 사용됩니다. 여기에는 수명이 짧은 메서드별 값과 메서드에서 참조되는 힙의 다른 개체에 대한 참조가 포함됩니다. 스택 메모리는 항상 LIFO(후입선출) 순서로 참조됩니다. 메서드가 호출될 때마다 스택 메모리에 새 블록이 생성되어 해당 메서드가 로컬 기본 값과 메서드의 다른 개체에 대한 참조를 보유합니다. 메서드가 종료되는 즉시 블록은 사용되지 않고 다음 메서드에 사용할 수 있게 됩니다. 스택 메모리 크기는 힙 메모리에 비해 매우 작습니다.

Java 프로그램의 힙 및 스택 메모리

간단한 프로그램으로 Heap과 Stack의 메모리 사용량을 알아봅시다.

package com.journaldev.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

}

  • 프로그램을 실행하자마자 모든 런타임 클래스를 힙 공간으로 로드합니다. main() 메서드가 1행에서 발견되면 Java Runtime은 main() 메서드 스레드에서 사용할 스택 메모리를 생성합니다.
  • 2행에서 기본 지역 변수를 생성하므로 main() 메서드의 스택 메모리에 생성되어 저장됩니다.
  • 3번째 줄에서 개체를 생성하므로 힙 메모리에 생성되고 스택 메모리에는 이에 대한 참조가 포함됩니다. 4번째 줄에서 Memory 객체를 생성할 때도 비슷한 과정이 발생합니다.
  • 이제 5번째 줄에서 foo() 메서드를 호출하면 foo() 메서드가 사용할 블록이 스택의 맨 위에 생성됩니다. Java는 값으로 전달되므로 Object에 대한 새 참조가 6번째 줄의 foo() 스택 블록에 생성됩니다.
  • 7번째 줄에서 문자열이 생성되고 힙 공간의 문자열 풀로 이동하며 참조가 foo() 스택 공간에 생성됩니다.
  • foo() 메서드는 8번째 줄에서 종료되는데 이때 스택에서 foo()에 할당된 메모리 블록이 해제됩니다.
  • 9행에서 main() 메소드가 종료되고 main() 메소드에 대해 생성된 스택 메모리가 소멸됩니다. 또한 프로그램은 이 줄에서 끝나므로 Java Runtime은 모든 메모리를 해제하고 프로그램 실행을 종료합니다.

Java 힙 공간과 스택 메모리의 차이점

위의 설명을 바탕으로 힙과 스택 메모리의 차이점은 다음과 같습니다.

  1. 힙 메모리는 애플리케이션의 모든 부분에서 사용되는 반면 스택 메모리는 하나의 실행 스레드에서만 사용됩니다.
  2. 객체가 생성될 때마다 항상 힙 공간에 저장되고 스택 메모리에는 객체에 대한 참조가 포함됩니다. 스택 메모리에는 로컬 기본 변수와 힙 공간의 개체에 대한 참조 변수만 포함됩니다.
  3. 힙에 저장된 개체는 전역적으로 액세스할 수 있지만 스택 메모리는 다른 스레드에서 액세스할 수 없습니다.
  4. 스택의 메모리 관리는 LIFO 방식으로 수행되는 반면 힙 메모리는 전역적으로 사용되기 때문에 더 복잡합니다. 힙 메모리는 Young-Generation, Old-Generation 등으로 구분되며 자세한 내용은 Java Garbage Collection을 참조하십시오.
  5. 스택 메모리는 수명이 짧은 반면 힙 메모리는 처음부터 애플리케이션 실행이 끝날 때까지 지속됩니다.
  6. -Xms 및 -Xmx JVM 옵션을 사용하여 시작 크기와 힙 메모리의 최대 크기를 정의할 수 있습니다. -Xss를 사용하여 스택 메모리 크기를 정의할 수 있습니다.
  7. 스택 메모리가 가득 차면 Java 런타임에서 java.lang.StackOverFlowError가 발생하지만 힙 메모리가 가득 차면 java.lang.OutOfMemoryError: Java 힙 공간 오류가 발생합니다. .
  8. 힙 메모리와 비교할 때 스택 메모리 크기는 매우 작습니다. 메모리 할당(LIFO)의 단순성으로 인해 스택 메모리는 힙 메모리에 비해 매우 빠릅니다.

이것이 Java 애플리케이션 측면에서 Java 힙 공간과 스택 메모리에 대한 전부입니다. Java 프로그램이 실행될 때 메모리 할당에 대한 의심이 해소되기를 바랍니다.

참조: https://en.wikipedia.org/wiki/Java_memory_model.