1. JVM 이란?
Java 프로그램은 OS 위에서 직접 실행되지 않고 JVM(Java Virtual Machine) 위에서 실행됩니다.
오늘은 이 JVM의 구조와 동작 방식에 대해서 알아보겠습니다.
JVM은 바이트코드를 해석하고 실행하는 가상 머신입니다.
JVM은 운영체제와 무관하게 자바 프로그램을 실행할 수 있게 하는 중개자 역할을 하며 'Write Once, Run Anywhere(한 번 작성하면 모든 곳에서 실행된다)' 라는 자바의 핵심 특징을 가능하게 합니다.
자바 바이트코드(Java bytecode): Java 소스 코드를 컴파일하여 얻은, 자바 가상머신(JVM)이 이해할 수 있는 중간 코드
2. JVM의 구성 요소

JVM의 구성요소는 크게 클래스 로더(Class Loader), 실행 엔진(Execution Engine), 런타임 데이터 영역(Runtime Data Area)로 나눌 수 있습니다. 하나씩 살펴보겠습니다.
1) 클래스 로더(Class Loader), 동적 로딩
클래스 로더는 동적 로딩을 통해 필요한 클래스들을 가져와서 런타임 데이터 영역으로 올립니다.
여기서 동적 로딩이란 실제 실행할 때 필요한 시점에만 클래스 파일을 메모리에 올린다는 뜻 입니다.
동적 로딩은 Loading -> Linking -> Initialization 순서로 이루어집니다.
각 과정은 다음과 같습니다.
- Loading (로드)
- .class 파일을 찾아서 JVM 메모리의 Method Area에 올림
- 클래스의 이름, 메서드, 필드, 접근 제어자 등 메타데이터를 저장
- Linking (링크)
- 로드된 클래스를 실제 사용할 수 있도록 검증 -> 준비 -> 해결 단계를 거침
- Verification (검증): 바이트 코드가 JVM 규칙에 맞는지 확인
- Preparation (준비): static 변수에 메모리 공간 할당, 기본값으로 초기화
- Resolution (해결): 클래스 이름 같은 심볼릭 참조를 실제 메모리 주소로 치환
- Initialization (초기화)
- static 변수에 실제 값을 넣고, static 블록 실행
- 이 시점에 클래스가 실제로 사용 가능한 상태가 됨
static 변수: 클래스에 1개만 존재하는 변수로 클래스가 로딩될 때 생성
심볼릭 참조: 클래스, 메서드 필드 등을 이름(문자열)로 참조해 둔 상태
2) 실행 엔진 (Execution Engine)
실행 엔진(Execution Engine)은 클래스 로더가 메모리에 올려둔 바이트코드(.class)를 실제로 CPU가 이해할 수 있는 기계어로 변환하고 실행하는 역할을 합니다. 실행 엔진은 인터프리터, JIT 컴파일러, Garbage Collector 세부분으로 나눌 수 있습니다.
- Interpreter
- .class 파일의 바이트 코드를 한 줄씩 익고 바로 실행
- 매번 해석해야 하므로 반복 실행되는 코드의 속도 저하
- JIT Compiler
- 자주 실행되는 코드를 감지하면 그 코드를 기계어(네이티브 코드)로 변환하여 캐싱(저장)
- 캐싱된 코드는 해석 없이 바로 실행할 수 있기 떄문에 속도 향상 -> Interpreter의 단점 보완
- Garbage Collector
- Heap 영역의 메모리 관리 담당
- 더 이상 참조되지 않는 객체를 찾아 메모리에서 제거
- 개발자가 직접 메모리를 해제할 필요가 없어서 메모리 누수 위험을 낮춤
Garbage Collector는 다른 포스팅에서 좀 더 깊게 다뤄보겠습니다.
3) 런타임 데이터 영역(Runtime Data Area)
런타임 데이터 영역은 JVM이 프로그램을 실행하면서 실제로 데이터를 저장하고 관리하는 메모리 공간입니다.
자바 프로그램이 실행될 때 생성되는 모든 변수, 객체, 메서드 정보 등이 이 영역에서 관리됩니다.
런타임 데이터 영역은 크게 5가지로 나눌 수 있습니다.
- Method Area
- 클래스 로더가 .class 파일을 읽어 들일 때 클래스 정보를 저장하는 공간
- 클래스 이름, 메서드, 필드, 접근 제어자, static 변수, 상수 풀 등이 저장
- JVM 전체에서 공유되는 영역
- Heap
- 프로그램 실행 중 생성되는 모든 객체 인스턴스와 배열이 저장되는 공간
- GC(Garbage Collector)가 관리하는 영역, 사용되지 않는 객체를 자동으로 제거
- JVM에서 가장 큰 메모리 영역, 모든 스레드가 공유
- Stack
- 메서드가 호출될 때마다 생성되는 지역변수, 매개변수 임시값 등을 저장
- 스레드 마다 독립적인 스택을 가짐
- 메서드 끝나면 사라짐
- PC Register
- 현재 실행 중인 명령어의 주소(위치)를 저장
- 스레드마다 독립적으로 존재하며, 다음 실행할 바이트 코드 명령의 주소를 보관
- Native Method Stack
- 네이티브 언어(실제 실행할 수 있는 기계어)된 메서드를 실행할 때 사용하는 스택
ex) C, C++ - 스택 구조
- 네이티브 언어(실제 실행할 수 있는 기계어)된 메서드를 실행할 때 사용하는 스택
예시를 위해 간단한 코드를 보겠습니다.
class Person {
static int population = 0;
String name;
public Person(String name) {
this.name = name;
population++;
}
public void sayHello() {
String greeting = "Hi, I'm " + name;
System.out.println(greeting);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("건영");
Person p2 = new Person("민수");
p1.sayHello();
}
}
- 프로그램 시작 시 Person 클래스가 로드
- Person.population(static 변수)가 Method Area에 만들어짐
- 값은 0
- p1 = new Person("건영") 실행 시
- new Person() 으로 Heap에 Person 객체 생성
- Heap 내부에 name = "건영" 저장
- p1은 Stack에 저장, Heap의 주소를 가리킴
- population++ 실행 -> Method Area의 값이 1이 됨
- p2 = new Person("민수") 실행 시
- 2번쨰 Person 객체 생성, Heap 내부에 name = "민수" 저장
- p2는 Stack에 저장, Heap의 두번째 객체 주소를 가리킴
- Method Area의 population 2로 증가
- p1.sayHello()
- sayHello() 메서드 호출 시 새로운 Stack 생성
- 지역변수 greeting이 stack에 저장, "Hi, I'm 건영" 출력
- 메서드 끝나면 해당 Stack 제거
여기서 기억할점은 p1 자체는 Stack에 있고, p1이 가리키는 객체(Person 인스턴스)는 Heap에 있다는 점 입니다.
즉 참조 변수(p1)은 Stack에 있고, 실제객체는 Heap에 있습니다.
3. JVM의 동작 방식
마지막으로 JVM이 어떻게 동작하는지 정리해보겠습니다.
- 컴파일 단계 (.java -> .class)
- 자바 컴파일러(javac)가 .java 파일을 바이트코드(.class)로 변환하는 단계
- 클래스 로더 (Class Loader)
- 필요한 바이트코드(.class)를 JVM으로 가져오는 역할
- 동적 로딩을 통해 필요한 클래스들을 가져와서 Runtime Data Area의 Method Area, Heap에 적재
- Loading -> Linking -> Initialization 순서로 진행
- 실행 엔진 (Execution Engine)
- 로드된 바이트 코드를 CPU가 이해할 수 있는 기계어로 변환하고 실행
- Interpreter + JIT Compiler로 동작
- 실행 중 불필요한 객체는 Garbage Collector가 관리
- Runtime Data Area
- 자바 프로그램이 실행되는 동안 필요한 모든 데이터가 저장
- 메서드 종료 후 stack 에 저장된 변수 제거
정리하자면, JVM은 자바 프로그램을 실행하기 위한 가상 머신으로, 클래스 로더 → 실행 엔진 → 런타임 데이터 영역 → GC 의 과정을 통해
바이트코드를 실제로 실행하고 메모리를 효율적으로 관리합니다.
'Backend > Java' 카테고리의 다른 글
| [Java] Annotation 어노테이션 알아보기, 커스텀 어노테이션 만들어보기 (1) | 2025.04.26 |
|---|