1. 개요
JVM의 런타임 데이터 영역은 크게 Method Area, Heap Area, Stack Area로 나누어 이해할 수 있다. 여기에 더해 PC Register, Native Method Stack 같은 영역도 있지만, 애플리케이션에서 메모리 구조를 설명할 때는 보통 이 세 영역을 중심으로 살펴본다.
각 영역은 저장하는 데이터의 성격과 생명주기가 다르다. 클래스 정보는 Method Area에, 실행 중 생성된 객체는 Heap Area에, 메서드 호출에 필요한 지역 변수와 연산 정보는 Stack Area에 저장된다.
2. 메모리 영역
2-1. Method Area
실행 중 어떤 class가 사용되면, JVM은 해당 class의 class file(*.class)을 읽고 분석한 뒤 class 관련 메타데이터를 이 영역에 저장한다. 예를 들어 클래스 이름, 부모 클래스 정보, 필드 정보, 메서드 정보, 런타임 상수 풀 등이 여기에 해당한다.
Method Area는 JVM 명세상의 논리적인 영역이며, 실제 구현 방식은 JVM 구현체와 버전에 따라 달라질 수 있다. 예를 들어 HotSpot JVM에서는 Java 8부터 클래스 메타데이터를 주로 Metaspace에 저장한다.
모든 method(class method, instance method)는 이 영역의 클래스 메타데이터와 함께 관리된다. 다만 호출 방식에는 차이가 있다. class method, 즉 static method는 instance 생성 없이 class 이름으로 바로 호출할 수 있고, instance method는 객체를 생성한 뒤 그 객체를 통해 호출해야 한다. Instance method는 보통 instance variable과 객체의 상태를 사용하기 때문이다.
2-2. Heap Area
Heap Area는 instance가 생성되는 공간이다. 실행 중 생성되는 객체와 배열은 이 영역에 저장된다. 즉, instance variable은 객체의 일부로서 Heap Area에 위치한다고 볼 수 있다.
Heap Area는 여러 thread가 공유하는 영역이므로 객체 생성과 해제 비용이 중요하다. 더 이상 참조되지 않는 객체는 Garbage Collector의 대상이 되며, 어떤 GC를 사용하느냐에 따라 메모리 회수 방식과 성능 특성이 달라질 수 있다.
관련된 내용에는 다음과 같은 것들이 있다.
2-3. Stack Area
Stack Area는 method의 작업에 필요한 공간이다. method가 호출되면 Call Stack에 해당 method를 위한 stack frame이 생성되며, 이 frame은 method가 작업을 수행하는 동안 local variable, 매개변수, 중간 연산 결과 등을 저장한다. 그리고 method가 작업을 마치면 할당되었던 stack frame은 제거된다.
Stack Area는 thread마다 별도로 생성된다. 따라서 각 thread는 자신만의 Call Stack을 가지며, 한 thread의 지역 변수는 다른 thread와 직접 공유되지 않는다. 반면 Heap Area에 있는 객체는 여러 thread가 함께 참조할 수 있으므로 동시성 문제가 발생할 수 있다.
2-4. 간단한 예시
public class MemorySample {
static int count = 0;
private String name;
public MemorySample(String name) {
this.name = name;
}
public void printName() {
String message = "name = " + name;
System.out.println(message);
}
}
위 예시에서 MemorySample 클래스의 메타데이터와 메서드 정보는 Method Area에 해당하는 영역에서 관리된다. new MemorySample("kim")처럼 객체를 생성하면 해당 instance는 Heap Area에 생성된다. printName()이 호출될 때 만들어지는 message 같은 지역 변수와 메서드 호출 정보는 Stack Area의 stack frame에서 관리된다.