JVM(Java Virtual Machine) 구조·메모리·동작 원리
자바 가상 머신(JVM)은 자바 애플리케이션을 실행·관리하는 핵심 엔진입니다. JVM이 바이트코드를 읽어 각 운영체제(OS)에서 동일하게 동작하도록 해 주기 때문에 “Write Once, Run Anywhere”가 가능해집니다.
JVM의 4대 핵심 역할
1. 바이트코드 실행
javac가 만든.class파일을 읽고 해석하거나 JIT 컴파일로 네이티브 기계어로 변환해 실행합니다.
2. 플랫폼 독립성 제공
- OS마다 다른 JVM 구현만 설치하면, 같은 바이트코드를 어디서나 실행할 수 있습니다.
3. 메모리 관리
- 가비지 컬렉션(GC) 으로 사용하지 않는 객체를 자동 회수해 개발자가 메모리를 직접 해제할 필요가 없습니다.
4. 안전성 보장
- 바이트코드 검증 단계로 악성·불법 접근을 차단해 애플리케이션의 안정성을 높입니다.
JVM 구성 요소 한눈에 보기
| 구성 요소 | 주요 기능 | 장점 | 단점 |
|---|---|---|---|
| 클래스 로더(Class Loader) | 필요한 클래스를 동적 로딩해 메모리에 적재 | 초기 구동 속도 ↑ | 잘못된 경로 설정 시 ClassNotFoundException |
| 메모리 영역 (Runtime Data Area) |
메서드 영역·힙·스택·PC 레지스터·네이티브 스택으로 분리 | 영역별 최적화 가능 | 힙 크기 튜닝이 복잡 |
| 실행 엔진 (Execution Engine) |
인터프리터 + JIT 컴파일러가 바이트코드 실행 | 반복 실행 시 속도 ↑ | JIT 웜업 구간 존재 |
| GC | 참조가 끊긴 객체 메모리 자동 회수 | 메모리 누수 방지 | GC 일시 중단(Pause) 가능성 |
| JNI(Native Interface) | C/C++ 등 네이티브 라이브러리 호출 | 성능 특화 로직 활용 | 플랫폼 종속성 증가 |
JVM 메모리 구조 상세 분석
메서드(Method) 영역
- 클래스 메타데이터·static 변수가 저장되며 모든 스레드가 공유합니다.
힙(Heap)
- 객체와 인스턴스 변수 저장소. GC가 관리하며, 영(Young)·노(Old) 영역으로 나뉘어 최적화됩니다.
스택(Stack)
- 각 스레드마다 독립적이며, 지역 변수·매개변수·프레임이 저장됩니다. 메서드가 끝나면 자동 해제됩니다.
PC 레지스터
- 현재 스레드가 다음에 실행할 바이트코드 주소를 보관합니다.
네이티브 메소드 스택
- C/C++로 작성된 네이티브 메소드 호출 시 필요한 스택 프레임을 관리합니다.
JVM 실행 과정 흐름도
-
컴파일 단계
.java→javac→.class(바이트코드)
-
클래스 로딩
Class Loader가
.class를 메서드 영역에 적재 -
바이트코드 실행
인터프리터가 즉시 해석 → 반복 구간은 JIT가 기계어로 변환
-
메모리 관리
미사용 객체를 GC가 탐지·회수
flowchart LR
A[소스 코드] --> B[javac 컴파일]
B --> C[바이트코드 .class]
C --> D[클래스 로더]
D --> E[실행 엔진]
E --> F[JIT / 인터프리터]
F --> G[실행 결과]
JVM의 장점과 한계
- 장점
- 플랫폼 독립성 → 다양한 OS 지원
- 자동 메모리 관리 → 개발 생산성↑
- 보안·안정성 → 바이트코드 검증, Sandbox 모델
- 단점
- 초기 실행 지연 → JIT 웜업, 클래스 로딩
- 메모리 오버헤드 → JVM 자체 힙·메타 공간 사용
실무 팁: 서버 애플리케이션에서 G1 GC, ZGC 같은 저지연 수집기를 선택하면 장시간 Pause를 크게 줄일 수 있습니다.
질문 정리
-
JIT 컴파일러가 항상 성능을 올리나요?
네, 반복 호출 메서드를 기계어로 캐싱해 속도를 향상시키지만, 첫 호출 시 컴파일 비용이 들어가 초기 지연이 발생합니다.
-
GC 일시 중단(Pause)이 왜 생기나요?
루트 객체 탐색·압축(compaction) 단계에서 모든 스레드를 잠시 멈춰야 하기 때문입니다. 최신 GC는 Pause 시간을 수~수십 ms 수준으로 줄였습니다.
-
메서드 영역이 PermGen이던데, 왜 Metaspace로 바뀌었나요?
JDK 8부터 PermGen이 Metaspace로 대체돼, OS 메모리를 동적으로 사용하여 OutOfMemoryError 위험을 완화했기 때문입니다.
-
네이티브 코드 호출 시 보안 문제는 없나요?
JNI 사용 시 JVM의 보안 검증을 우회할 수 있으므로, 입력 검증과 권한 관리(Policy File)가 필수입니다.
-
JVM 튜닝을 시작하려면 무엇을 봐야 하나요?
Xms/-Xmx힙 크기, GC 종류(XX:+UseG1GC)를 설정하고, JFR(Java Flight Recorder)·VisualVM으로 힙·스레드·GC 로그를 모니터링해 병목을 찾습니다.
댓글남기기