JVM
Last updated
Last updated
Java Virtual Machine
JVM이 OS에서 실행되면, Java 애플리케이션은 JVM하고만 상호작용하므로 OS에 종속되지 않는다. 대신, JVM은 OS에 종속적이다.
자바로 작성한 애플리케이션을 해당 운영체제가 이해할 수 있도록 변환하여 전달한다.
바이트 코드를 기계어로 변환하고 실행한다.
아래 그림과 같이 자바 컴파일러(javac)와는 다른 모듈이다.
바이트 코드
JVM이 이해할 수 있는 기계어
바이트 코드의 각 명령어는 1바이트 크기의 Opcode와 추가 피연산자로 이루어져 있다.
컴파일된 바이트 코드 형태의 클래스들이 JVM에 전달되면, 아래 그림과 같은 흐름으로 코드가 실행되게 된다.
내부 구성 요소인 Class Loader, Runtime Data Areas, Execution Engine에 대해서는 아래에서 간략히 설명한다.
컴파일된 .class 파일에서 바이트 코드를 읽고 메모리에 저장한다.
한번에 모든 클래스를 로딩하는 것이 아닌, 필요할 때마다 클래스나 리소스를 로딩한다.
바이트코드를 Loading → Linking → Initialization 의 순서로 처리한다.
Loading: 클래스를 읽어오는 과정
Linking: 레퍼런스를 연결하는 과정
Initialization: static 값들을 초기화하고 변수에 할당하는 과정
앱 실행을 위해 사용되는 JVM 메모리 영역
구성
PC(Program Counter) Registers
스레드 별로 생성
현재 실행 중인 명령(오프셋 / 스택 프레임)을 가리키는 포인터를 저장하는 영역
Java Virtual Machine Stacks (Stack Area, Java Stack)
스레드 별로 생성
메서드 실행 관련 정보를 저장하는 영역
메서드가 호출되면 스택에 프레임 단위로 메서드 정보가 쌓이게 된다.
Heap
JVM 실행 시 생성
모든 객체 인스턴스/배열에 대한 메모리가 할당되는 영역
GC가 도는 영역은 보통 Heap 영역뿐이다.
Method
JVM 실행 시 생성
클래스의 구조 등에 대한 정보가 메모리에 할당
Native Method Stacks
스레드 별로 생성
네이티브 코드 실행에 관련된 정보를 저장하는 영역
메모리 영역에 있는 데이터를 가져와 해당하는 작업 수행
JIT 컴파일러, 인터프리터, GC가 존재한다.
자주쓰이는 코드는 JIT 컴파일러를 통해 미리 네이티브 코드(기계어)로 변환해두고, 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다.
GC는 더이상 참조되지 않는 객체를 모아 메모리를 해제한다.
JVM과 네이티브 라이브러리 간 이진 호환성을 위한 인터페이스
네이티브 언어로 작성된 메서드 호출, 데이터 전달과 메모리 관리 등 수행
실행 시 메모리의 Native Method Stacks에 정보가 저장된다.
네이티브 메서드의 구현체를 포함한 플랫폼 별 라이브러리