자바 애플리케이션이 실행되면 JVM은 운영 체제(OS)로부터 메모리를 할당받고, 여러 단계의 과정을 거쳐 실행된다.
1. 클래스 로딩과 컴파일
- 자바 소스 파일(.java)은 컴파일러를 통해 바이트 코드(.class)로 변환된다.
- 클래스 로더(Class Loader)가 변환된 바이트 코드를 JVM으로 로딩한다.
- 클래스 로더는 모든 클래스를 한 번에 로딩하지 않고, 필요한 순간에 동적으로 메모리에 적재한다.
- 로딩된 바이트 코드는 실행 엔진(Execution Engine)에 의해 해석된다.
2. 실행 엔진(Execution Engine)
JVM의 실행 엔진은 로딩된 바이트 코드를 운영체제에 맞게 기계어로 변환하여 실제로 실행하는 역할을 한다.
- 인터프리터(Interpreter): 바이트 코드를 한 줄씩 읽어 즉시 실행한다.
- JIT(Just-In-Time) 컴파일러: 반복 실행되는 코드를 미리 컴파일하여 속도를 높인다.
- 가비지 컬렉터(GC): 더 이상 참조되지 않는 객체를 정리하여 메모리를 확보한다.
3. JVM의 메모리 구조 (Runtime Data Area)
JVM은 실행 중 다양한 데이터를 저장하기 위해 여러 메모리 영역을 활용한다.
메서드(Method) 영역
- static 변수, 필드, 메서드 정보 등을 저장하며 여러 스레드가 공유한다.
- Runtime Constant Pool에 상수를 따로 관리한다.
힙(Heap) 영역
- new 연산자로 생성된 객체, 배열 등을 저장한다.
- Young Generation (Eden, S0, S1): 생명주기가 짧은 객체가 위치하며 GC가 자주 실행된다.
- Old Generation: 오랜 기간 사용되는 객체가 저장되며 주기적으로 GC가 실행된다.
스택(Stack) 영역
- 각 스레드마다 독립적인 공간을 가지며 메서드 실행에 필요한 데이터를 저장한다.
- 메서드 호출 시 스택 프레임이 생성되고, 실행 종료 시 제거된다.
- 스택 프레임은 메서드 실행 중 지역 변수, 매개변수 등을 저장하는 공간이다.
PC 레지스터 및 네이티브 메서드 스택
- 현재 실행 중인 명령어의 주소를 저장하는 PC 레지스터가 있다.
- JNI(Java Native Interface)를 통해 다른 언어(C/C++)의 코드와 연동할 수 있다.
4. 가비지 컬렉션과 Stop-the-World
JVM은 불필요한 객체를 자동으로 정리하는 GC(Garbage Collector)를 수행한다.
그러나 GC 실행 시 JVM이 잠시 멈추는 Stop-the-World 현상이 발생할 수 있다.
GC 튜닝을 통해 Stop-the-World 시간을 최소화하면 애플리케이션 성능을 높일 수 있다.
5. 클래스 로더의 메모리 관리
클래스 로더는 .class 파일을 로딩(Loading), 링크(Linking), 초기화(Initialization) 과정을 통해 런타임 데이터 영역에 배치한다.
클래스를 필요할 때만 동적으로 로딩하는 방식으로 메모리를 효율적으로 사용한다.