자바 바이트코드를 메모리에 적재 클래스 로딩은 동적으로 수행 (필요할 때마다 .class 파일을 찾아 읽음)
클래스 로딩은 아래 단계를 거친다.
로딩(Loading): .class 파일을 읽고 JVM 내부 메모리에 적재.
검증(Verification): 바이트코드가 올바른 형식인지 검사 (보안 목적).
준비(Preparation): 정적 변수(static field)에 대해 기본 메모리 할당.
분석(Resolution): 상속 및 인터페이스 관계를 확인하고, 참조된 클래스를 해석.
초기화(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이 제공하는 일관된 실행 환경에서 프로그램을 개발하고 실행할 수 있다.