JVM

JVM - 구조

mak-ing 2025. 2. 10. 23:01

 

 

JVM - WORA

플랫폼 독립성 소프트웨어는 발전할수록 더 많은 환경에서 실행할 수 있는 유연성을 필요로 한다. 그러나 과거에는 운영체제(OS)나 하드웨어(CPU)에 따라 실행 방식이 달라지는 문제가 있었다.

mak-ing.tistory.com

 

앞서 설명했듯이, JVM은 자바 프로그램이 하드웨어와 운영체제(OS)에서 독립적으로 실행될 수 있도록 하는 가상화된 실행 환경이다.

JVM은 바이트코드를 실행하는 과정에서 가상의 운영체제처럼 동작하며, 메모리 관리, 클래스 로딩, 실행 엔진 등의 핵심 기능을 수행한다.


 

JVM, OS

 

JVM은 실행 환경을 제공하지만, 궁극적으로 OS의 도움을 받아 동작한다.

JVM과 OS의 관계를 크게 다음 세 가지로 정리할 수 있다.

 

JVM은 OS 위에서 실행되는 프로세스

  • 자바 애플리케이션을 실행하면, java 프로세스가 생성된다.
  • OS는 JVM에게 프로세스 실행을 위한 메모리와 CPU 리소스를 할당한다.
  • JVM은 단일 프로세스로 실행되지만, 내부적으로 여러 개의 Java 스레드를 생성하며, 이들은 OS의 네이티브 스레드로 매핑된다.

 

JVM은 OS의 API를 호출하여 시스템 자원을 사용

  • 자바 프로그램이 파일을 읽거나 네트워크 통신을 할 때, JVM이 OS의 네이티브 API를 호출한다.
  • 예를 들어, System.out.println()은 결국 OS의 표준 출력(stdout)으로 전달된다.
  • 자바의 멀티스레딩은 기존에는 OS 스레드와 1:1로 매핑되었지만, 최신 버전에서는 JVM이 직접 관리하는 가상 스레드를 지원하여 더 많은 동시 실행을 가능하게 한다.

 

JVM은 OS에 의해 제어되며, OS와 독립적인 실행 환경을 제공

  • 자바 코드는 OS에 직접 의존하지 않지만, JVM 자체는 OS에 의존하며, OS API를 활용하여 파일, 네트워크, 스레드 등의 기능을 수행한다.
  • JVM이 크로스플랫폼을 지원하는 이유는, 각 OS에 맞는 JVM 구현이 존재하기 때문이다.
    • Windows JVM, Linux JVM, Mac JVM 등 OS에 맞는 네이티브 코드가 포함되어 있다.

JVM 구성 요소

JVM

출처: https://softwareperformancenotes.github.io/jvmarch/


Class Loader Subsystem

자바 바이트코드를 메모리에 적재
클래스 로딩은 동적으로 수행 (필요할 때마다 .class 파일을 찾아 읽음)

 

클래스 로딩은 아래 단계를 거친다.

  1. 로딩(Loading): .class 파일을 읽고 JVM 내부 메모리에 적재.
  2. 검증(Verification): 바이트코드가 올바른 형식인지 검사 (보안 목적).
  3. 준비(Preparation): 정적 변수(static field)에 대해 기본 메모리 할당.
  4. 분석(Resolution): 상속 및 인터페이스 관계를 확인하고, 참조된 클래스를 해석.
  5. 초기화(Initialization): 정적 변수에 실제 값을 할당하고, static block 실행.

JVM에는 여러 클래스 로더가 존재한다.

  • Bootstrap ClassLoader - rt.jar 같은 기본 라이브러리 로딩
  • Extension ClassLoader - lib/ext 디렉토리에 있는 확장 라이브러리 로딩
  • Application ClassLoader - 우리가 작성한 애플리케이션 클래스 로딩
  • Custom ClassLoader - 개발자가 직접 정의한 클래스 로더

Runtime Data Area

JVM의 메모리는 여러 영역으로 나누어 관리
각각의 영역은 자바 프로그램 실행에 필요한 데이터와 명령을 저장

 

Heap

  • 모든 객체가 저장되는 공간.
  • JVM의 가비지 컬렉션(GC)이 관리.
  • GC 방식에 따라 힙 메모리의 구성이 달라질 수 있음.

 

Stack

  • 스레드마다 독립적으로 할당되는 메모리 공간.
  • 메서드 호출 시 프레임(Stack Frame)이 생성되며, 지역 변수, 매개변수, 리턴 값, 메서드 실행 정보가 저장.
  • 메서드가 종료되면 해당 프레임이 제거.

 

Method Area

  • 클래스의 메타데이터(클래스명, 변수, 메서드 정보 등)가 저장.
  • static 변수와 Constant Pool(상수 풀)도 포함.

 

PC Register (PC 레지스터, 프로그램 카운터)

  • 현재 실행 중인 바이트코드 명령어의 주소를 저장.

 

Native Method Stack (네이티브 메서드 스택)

  • JNI(Java Native Interface)를 통해 C/C++ 등의 네이티브 코드가 실행될 때 사용.

Execution Engine

바이트코드를 실제 CPU에서 실행 가능한 기계어로 변환

 

인터프리터 (Interpreter)

  • 바이트코드를 한 줄씩 해석하고 실행.
  • 실행 속도가 느리지만, 빠르게 시작할 수 있음.

 

JIT (Just-In-Time) 컴파일러

  • 자주 실행되는 바이트코드를 네이티브 코드로 변환하여 캐싱.

 

핫스팟(HotSpot) 기술을 활용하여 성능 최적화.

  • Inlining (자주 호출되는 메서드를 직접 삽입)
  • Escape Analysis (불필요한 객체 생성을 제거)
  • Loop Optimization (반복문 최적화)

 

JNI - Java Native Interface

자바 프로그램이 C, C++ 등의 네이티브 코드와 상호작용할 수 있도록 돕는 인터페이스

 

  • 운영체제의 네이티브 API 호출 (예: Windows API, POSIX API).
  • 하드웨어 제어, 네트워크, 그래픽 등의 성능이 중요한 작업을 지원.
  • JNI를 사용하면 자바의 플랫폼 독립성이 깨질 수 있음.

 


 

마무리

 

JVM은 운영 체제 위에서 동작하는 실행 환경이다

 

JVM은 단순한 인터프리터가 아니라, OS처럼 메모리 관리, 실행 엔진, 네이티브 인터페이스 지원 등의 역할을 수행하며, 자바 프로그램이 독립적인 실행 환경에서 동작할 수 있도록 한다. 그러나 JVM은 OS 위에서 실행되는 하나의 프로세스이므로, OS의 리소스를 할당받아 사용하며, 필요한 경우 JNI를 통해 네이티브 API를 호출하여 OS 및 하드웨어와 상호작용할 수 있다.

 

즉, JVM은 OS 위에서 동작하며 OS의 세부적인 요소에 직접 접근하지 않아도 되는 실행 환경이다.

우리는 JVM이 제공하는 메모리 관리, 애플리케이션 실행, 네이티브 코드 연동 기능을 활용하여 OS의 복잡한 구조를 신경 쓰지 않고도 자바 애플리케이션을 개발하고 실행할 수 있다.

 

JVM은 운영체제와 하드웨어 사이의 추상 계층을 형성하여, OS별 차이점을 감추고 개발자가 OS에 독립적인 코드를 작성할 수 있도록 돕는다. 덕분에 우리는 운영체제마다 다른 파일 시스템 관리 방식이나, 하드웨어 접근 방식을 직접 다룰 필요 없이, JVM이 제공하는 일관된 실행 환경에서 프로그램을 개발하고 실행할 수 있다.