2 분 소요

자바 가상 머신(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 실행 과정 흐름도

  1. 컴파일 단계

    • .javajavac.class (바이트코드)
  2. 클래스 로딩

    Class Loader가 .class를 메서드 영역에 적재

  3. 바이트코드 실행

    인터프리터가 즉시 해석 → 반복 구간은 JIT가 기계어로 변환

  4. 메모리 관리

    미사용 객체를 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를 크게 줄일 수 있습니다.


질문 정리

  1. JIT 컴파일러가 항상 성능을 올리나요?

    네, 반복 호출 메서드를 기계어로 캐싱해 속도를 향상시키지만, 첫 호출 시 컴파일 비용이 들어가 초기 지연이 발생합니다.

  2. GC 일시 중단(Pause)이 왜 생기나요?

    루트 객체 탐색·압축(compaction) 단계에서 모든 스레드를 잠시 멈춰야 하기 때문입니다. 최신 GC는 Pause 시간을 수~수십 ms 수준으로 줄였습니다.

  3. 메서드 영역이 PermGen이던데, 왜 Metaspace로 바뀌었나요?

    JDK 8부터 PermGen이 Metaspace로 대체돼, OS 메모리를 동적으로 사용하여 OutOfMemoryError 위험을 완화했기 때문입니다.

  4. 네이티브 코드 호출 시 보안 문제는 없나요?

    JNI 사용 시 JVM의 보안 검증을 우회할 수 있으므로, 입력 검증과 권한 관리(Policy File)가 필수입니다.

  5. JVM 튜닝을 시작하려면 무엇을 봐야 하나요?

    • Xms/-Xmx 힙 크기, GC 종류(XX:+UseG1GC)를 설정하고, JFR(Java Flight Recorder)·VisualVM으로 힙·스레드·GC 로그를 모니터링해 병목을 찾습니다.

카테고리:

업데이트:

댓글남기기