JVM의 메모리 영역으로, 자바 애플리케이션을 실행할 때 사용되는 데이터를 적재하는 영역이다.
이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나뉜다.

클래스 파일의 정보(메타데이터), static 변수, 메서드 정보, 생성자, 상수(Constant Pool) 등을 저장하는 영역.
JVM이 실행될 때 Class Loader에 의해 클래스를 로드하여 Method Area에 저장.
모든 스레드가 공유한다 !
JVM이 종료될 때까지 유지되며, 오래 사용될 경우 OutOfMemoryError 발생 가능.
static final 변수는 컴파일 타임에 값이 확정되면 Method Area(Constant Pool)에 저장되지만, 일반 final 인스턴스 변수는 Heap에 저장됨.
new 키워드로 생성된 객체와 배열이 저장되는 영역 (동적 할당된 객체들의 저장소).
Method Area에 로드된 클래스만 객체 생성 가능.
Garbage Collector(GC)가 참조되지 않는 객체를 자동으로 제거.
Heap은 JVM에서 가장 큰 메모리 공간이며, 여러 개의 스레드가 공유하는 영역이다.
지역 변수, 매개 변수, 리턴 값, 연산에 사용되는 임시 값 등이 저장되는 영역.

스택 프레임(Stack Frame)이란?
각 메소드 실행을 위한 독립적인 공간으로, 해당 메소드의 지역 변수, 매개 변수, 연산 결과, 리턴 값 등이 저장됨.
호출된 메소드가 완료되면 해당 스택 프레임이 제거되며, 메모리가 자동으로 관리됨.
이러한 구조 덕분에 메소드가 재귀 호출되면 스택이 계속 쌓이게 되며, 너무 깊어지면 StackOverflowError가 발생할 수 있음.
기본 타입(Primitive Type) 변수(int, double, boolean 등)와 객체의 참조 변수(주소)가 저장됨.
예시
int a = 10; // 'a'는 Stack에 저장됨
Person p = new Person(); // 'p'는 Stack에 저장, 실제 객체는 Heap에 저장됨

각 스레드마다 독립적인 공간을 가진다 !
예시
class Task implements Runnable { @Override public void run() { int localVar = 0; // 각 스레드마다 독립적인 공간 localVar++; System.out.println(Thread.currentThread().getName() + " - localVar: " + localVar); } } public class Main { public static void main(String[] args) { Thread t1 = new Thread(new Task(), "Thread-1"); Thread t2 = new Thread(new Task(), "Thread-2"); t1.start(); t2.start(); } } //실행 결과 Thread-1 - localVar: 1 Thread-2 - localVar: 1
JVM이 현재 실행 중인 바이트코드 명령어의 주소(메모리 위치)를 저장하는 공간
각 스레드마다 독립적인 PC Register를 가짐
역할
메서드가 실행되면, 해당 메서드의 바이트코드 명령어를 하나씩 실행해야 하는데, JVM은 현재 실행 중인 명령어의 주소(Program Counter, PC)를 저장해야 함.
이를 위해 각 스레드는 자신의 PC Register를 가지며, 현재 실행 중인 바이트코드의 위치를 추적함.
즉, 현재 실행 중인 코드의 다음 실행 위치를 저장하는 역할.
멀티스레드 환경에서 중요한 이유
여러 개의 스레드가 동시에 실행되면, 각각 실행하는 코드의 위치가 다를 수 있음.
각 스레드는 자신만의 PC Register를 가지므로, 서로 다른 명령어를 실행할 수 있음.
만약 모든 스레드가 하나의 PC Register를 공유했다면, 어떤 스레드가 실행되었는지 알 수 없어서 프로그램이 정상적으로 동작하지 않음.
쉽게 말하면, PC Register는 JVM이 "지금 어디까지 실행했는지"를 추적하는 역할을 하는 공간이고, 각 스레드마다 독립적으로 관리됨.
Java가 아닌 네이티브 코드(C, C++ 등)로 작성된 메서드를 실행할 때 사용하는 메모리 영역
JNI (Java Native Interface)를 통해 네이티브 코드를 호출할 때 활용됨.
역할
만약 네이티브 메서드를 사용하지 않는다면?
예제
class NativeExample { // 네이티브 메서드 선언 (C 코드에서 구현) public native void sayHello(); static { System.loadLibrary("NativeLib"); // 네이티브 라이브러리 로드 } }위 코드에서 sayHello() 메서드는 Java가 아닌 C 코드에서 구현되며, JVM은 이 메서드를 실행할 때 Native Method Stack을 사용함.
쉽게 말하면, 네이티브 메서드 스택은 Java가 아닌 C, C++ 같은 네이티브 코드를 실행할 때 필요한 스택 공간
| 구분 | Heap | Stack |
|---|---|---|
| 저장 대상 | 객체(인스턴스), 배열 | 지역 변수, 매개 변수, 참조 변수 |
| 관리 방식 | GC(Garbage Collector) 자동 관리 | 메소드 호출 시 할당, 종료 시 해제 |
| 속도 | 상대적으로 느림 (GC 개입) | 상대적으로 빠름 |
| 메모리 할당 | 동적 할당 (new 키워드 등) | 정적 할당 (컴파일 시 결정) |
| 예제 | new Counter(); 객체 저장 | Counter c; 참조 변수 저장 |
static final 상수는 Method Area의 Constant Pool에 저장될 수도 있지만, 일반 final 인스턴스 변수는 Heap에 저장됨.
String 객체는 리터럴이면 Method Area, new String("abc")이면 Heap에 저장됨.
Heap의 객체를 가리키는 레퍼런스 변수는 Stack에 저장됨.
Stack은 메소드 단위로 메모리를 관리하며, 호출이 끝나면 자동으로 해제되므로 메모리 효율이 높음.