JVM?
JVM은 자바 애플리케이션을 실행하는 데 필요한 환경을 제공한다.
JVM은 자바 코드를 컴파일된 바이트코드로 받아 이를 운영체제와 하드웨어에 맞게 기계어로 변환하고, 메모리 관리 및 실행 환경을 제공한다.
JVM의 동작 과정은 다음과 같은 컴포넌트로 이루어지낟.
1. 클래스 로더 시스템
- 클래스 로딩
- 자바 프로그램을 실행할 때 .class 파일(바이트코드)을 메모리로 로드하는 단계
- 클래스 로더는 로딩 중인 클래스의 위치와 존재 여부를 확인한다.
- 링킹
- 클래스가 메모리에 로드되면 참조된 다른 클래스나 메서드를 링크하는 과정이 필요하다.
- 링크는 검증, 준비, 해석 세 단계로 이루어진다.
- 초기화
- 클래스의 static 블록과 static 변수들이 초기화된다.
2. 메모리 영역
JVM은 메모리를 다섯 개의 주요 영역으로 나누어 관리한다.
- 메소드 영역
- 모든 클래스의 구조적 정보(클래스, 메소드, 인터페이스, 상수)를 저장하는 영역이다.
- 메소드 영역에는 클래스 로더가 로드한 클래스 정보와 메서드, static 변수 등이 포함된다.
- 힙
- 동적으로 생성된 객체와 인스턴스 변수를 저장하는 영역이다.
- Garbage Collector가 관리하여 사용하지 않는 객체를 정리한다.
- 스택
- 각 스레드별로 생성되는 지역 변수를 저장하는 영역으로 메서드 호출 시 스택 프레임이 생성된다.
- PC 레지스터
- 각 스레드가 현재 실행 중인 바이트코드의 주소를 저장한다.
- 네이티브 메서드 스택
- 자바 외의 네이티브 메서드가 호출될 때 사용된다.
3. 실행 엔진
- 인터프리터
- 바이트코드를 한 줄씩 읽어서 해석하고 실행하는 역할을 한다.
- 초기에는 인터프리터 방식으로 빠르게 실행되지만 성능은 다소 떨어질 수 있다.
- JIT 컴파일러
- 인터프리터의 단점을 보완하기 위해, 자주 실행되는 바이트코드 영역을 기계어로 컴파일해 캐시에 저장하고 재사용한다.
- JIT(Just In Time) 컴파일러는 런타임에 바이트코드를 네이티브 코드로 변환하여 성능을 높인다.
- Garbage Collector
- Heap 메모리에서 더 이상 사용되지 않는 객체를 자동으로 정리하여 메모리 누수를 방지하고 메모리 관리 효율을 높인다. 다양한 GC 알고리즘이 제공된다.
4. JNI(Java Native Interface)
자바 애플리케이션에서 C/C++ 같은 네이티브 코드를 호출할 때 사용하는 인터페이스이다.
JNI는 네이티브 메서드를 호출하거나 네이티브 메서드에서 자바로 돌아오는 데 필요한 환경을 제공한다.
5. JVM의 전체 동작 과정
- 자바 코드 컴파일
- .java 파일을 자바 컴파일러가 .class파일로 컴파일한다.
- 클래스 로딩
- JVM의 클래스 로더가 필요한 .class 파일을 메모리에 로드한다.
- 실행 엔진 실행
- 인터프리터와 JIT 컴파일러가 바이트코드를 기계어로 변환해 실행한다.
- Garbage Collection
- 애플리케이션이 실행되는 동안 자동으로 메모리를 정리한다.
JVM 동작의 장점과 단점
- 장점
- 플랫폼 독립적인 자바 코드 실행
- 메모리 관리 자동화
- 동적 클래스 로딩
- 단점
- 다른 언어보다 초기 실행 속도가 느리다.
- JIT 컴파일에 의한 런타임 오버헤드