Java 개발자 필수 기초: JVM 메모리 구조 파헤치기 (스택, 힙, 메소드 영역)
우리가 작성한 Java 코드는 어떻게 컴퓨터 메모리 위에서 살아 움직일까요? 왜 메소드가 끝나면 그 안의 변수는 사라지는데, new
로 만든 객체는 계속 남아있을까요? 이 모든 질문의 해답은 JVM(자바 가상 머신)의 메모리 구조에 있습니다.
JVM이 메모리를 어떻게 체계적으로 나누어 사용하는지 이해하는 것은 메모리 누수를 방지하고, 성능을 최적화하며, 버그를 잡는 데 매우 중요한 기초 체력입니다.
오늘은 JVM 메모리의 핵심 영역인 **스택(Stack), 힙(Heap), 메소드 영역(Method Area)**을 알아보고, 실제 코드가 각 영역에 어떻게 할당되는지 그 과정을 따라가 보겠습니다.
JVM 메모리의 3가지 핵심 영역
JVM은 메모리를 크게 세 가지 영역으로 구분하여 관리합니다.
- 스택 영역 (Stack Area) :
메소드의 작업실
- 역할: 메소드 호출 시 필요한 지역 변수, 매개변수, 그리고 연산의 중간 결과 등이 저장되는 임시 작업 공간입니다. 스레드마다 별도의 스택이 할당됩니다.
- 특징: 메소드가 호출될 때 스택 프레임(Stack Frame)이 생성되고, 메소드 실행이 끝나면 해당 프레임이 제거됩니다(LIFO: Last-In, First-Out). 개발자가 직접 초기화해야 하며, 그렇지 않으면 컴파일 에러가 발생합니다.
- 힙 영역 (Heap Area) :
객체들의 아파트
- 역할:
new
키워드로 생성된 모든 인스턴스(객체)와 배열이 저장되는 공간입니다. - 특징: 가비지 컬렉터(Garbage Collector)가 더 이상 참조되지 않는 객체를 찾아 메모리에서 해제합니다. 숫자 타입은 0, boolean은 false, 참조 타입은 null 등으로 자동 초기화가 진행됩니다. 모든 스레드가 공유하는 영역입니다.
- 역할:
- 메소드 영역 (Method Area or Static Area) :
클래스의 설계도 보관소
- 역할: 클래스의 구조 정보(바이트 코드), 메소드 정보, 그리고
static
으로 선언된 변수 및 필드가 저장됩니다. - 특징: JVM이 시작될 때 생성되며, 프로그램이 종료될 때까지 유지됩니다. 모든 스레드가 공유합니다.
- 역할: 클래스의 구조 정보(바이트 코드), 메소드 정보, 그리고
코드로 보는 메모리 할당의 순간들
아래 예제 코드를 통해 각 요소가 어느 시점에 어떤 메모리 영역에 할당되는지 살펴보겠습니다.
public class MemoryExample {
static int staticField = 10; // static 필드
int instanceField = 20; // 인스턴스 필드
static void staticMethod() {
System.out.println("Static Method");
}
void instanceMethod() {
System.out.println("Instance Method");
}
public static void main(String[] args) {
int localVar = 30; // 지역 변수
// 1. 클래스 멤버 접근
MemoryExample.staticMethod();
System.out.println(MemoryExample.staticField);
// 2. 인스턴스 생성 및 멤버 접근
MemoryExample example = new MemoryExample(); // 객체 생성
example.instanceMethod();
System.out.println(example.instanceField);
}
}
1단계: 클래스 로드 시점 - 설계도를 펼치는 순간
JVM이 MemoryExample.class
파일을 읽어들일 때 발생합니다.
staticField
와staticMethod()
코드,instanceMethod()
코드는 **메소드 영역(Method Area)**에 올라갑니다.- 이들은 프로그램 전체에서 공유되며, 언제든 접근할 수 있는 상태가 됩니다.
2단계: main
메소드 실행 시점 - 작업의 시작
main
메소드가 호출되면 다음과 같이 메모리가 할당됩니다.
main
메소드를 위한 새로운 스택 프레임이 **스택 영역(Stack Area)**에 생성됩니다.main
메소드 내부의 지역 변수인localVar
는 이 스택 프레임 안에 저장됩니다.MemoryExample.staticMethod()
를 호출하거나staticField
에 접근할 때는 이미 메소드 영역에 있는 코드를 실행하거나 값을 읽어올 뿐, 새로운 메모리 할당은 거의 없습니다.
3단계: 객체 생성 시점 - 실제 제품을 만드는 순간
new MemoryExample()
코드가 실행되는 순간입니다.
new
키워드에 의해MemoryExample
객체가 **힙 영역(Heap Area)**에 생성됩니다.- 객체의 멤버 변수인
instanceField
는 이 힙 영역의 객체 내부에 자리를 잡습니다. main
메소드의 지역 변수인example
은 스택 영역에 생성되며, 힙에 생성된 객체의 **참조 주소(주소값)**를 저장합니다.example.instanceMethod()
를 호출하면, 메소드 영역에 있는 메소드 코드를 사용하되, 이 메소드 실행을 위한 새로운 스택 프레임이 스택 영역에 추가로 생성됩니다.
한눈에 보는 메모리 할당 요약
메모리 영역 | 저장되는 내용 | 예시 코드 |
---|---|---|
메소드 영역 (Method Area) | 클래스 코드, static 변수/메소드 |
staticField , staticMethod() , instanceMethod() |
힙 영역 (Heap Area) | new 로 생성된 모든 객체와 배열, 인스턴스 변수 |
new MemoryExample() , instanceField |
스택 영역 (Stack Area) | 지역 변수, 매개변수, 객체의 참조 주소 | localVar , example |
결론
JVM이 메모리를 스택, 힙, 메소드 영역으로 나누어 관리하는 덕분에 우리는 효율적이고 안정적인 애플리케이션을 만들 수 있습니다.
- 스택은 빠른 작업 처리를 위한 임시 공간으로,
- 힙은 객체들이 오래도록 머무는 거주 공간으로,
- 메소드 영역은 모두가 공유하는 공공 도서관처럼 작동합니다.
'프로그래밍 언어 > java' 카테고리의 다른 글
[Java] equals overriding 과 hash code (0) | 2024.08.11 |
---|---|
[Java] final과 static: '불변'과 '공유'의 미학 (feat. JVM 메모리 구조) (0) | 2024.07.28 |
객체 지향 언어 (0) | 2024.07.09 |
[자바] 입력받기 (0) | 2024.07.09 |
자바의 기본개념 (0) | 2024.07.08 |