JVM(Java Virtual Machine)
자바 어플리케이션을 클래스 로드를 통해 읽어들여, Java API와 함께 실행한다. 실제 자바 프로그램의 실행주체가 된다.
JVM은 물리적 머신과 별개의 가상 머신을 기반으로 자바를 작동시키기 때문에 어떤 하드웨어에서 작동을 시키든 실행코드를 변경하지 않고 동일하게 작동시킬 수 있다.
JVM의 특징
- 스택 기반의 가상 머신: 대표적인 컴퓨터 아키텍처인 인텔 x86 아키텍처나 ARM 아키텍처와 같은 하드웨어가 레지스터 기반으로 동작하는 데 비해 JVM은 스택 기반으로 동작한다.
- 심볼릭 레퍼런스: 기본 자료형(primitive data type)을 제외한 모든 타입(클래스와 인터페이스)을 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다.
- 가비지 컬렉션(garbage collection): 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 파괴된다.
- 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장: C/C++ 등의 전통적인 언어는 플랫폼에 따라 int 형의 크기가 변한다. JVM은 기본 자료형을 명확하게 정의하여 호환성을 유지하고 플랫폼 독립성을 보장한다.
- 네트워크 바이트 오더(network byte order): 자바 클래스 파일은 네트워크 바이트 오더를 사용한다. 인텔 x86 아키텍처가 사용하는 리틀 엔디안이나, RISC 계열 아키텍처가 주로 사용하는 빅 엔디안 사이에서 플랫폼 독립성을 유지하려면 고정된 바이트 오더를 유지해야 하므로 네트워크 전송 시에 사용하는 바이트 오더인 네트워크 바이트 오더를 사용한다. 네트워크 바이트 오더는 빅 엔디안이다.
JVM의 구조

크게 클래스 로더, Runtime Data Area, Execution Engine 3가지로 이루어져 있다.
- 클래스 로더
Runtime 시점에 클래스를 로딩하며, 클래스의 인스턴스를 생성하면 이 로더를 통해서 메모리에 로드해준다. 클래스는 참조되는 순간 동적으로 load와 link가 이루어진다고 한다. (Dynamic Loading)
- Runtime Data Area
JVM이 프로그램 실행을 위해 OS에 할당받은 메모리 공간. 크게 5가지 영역으로 나눌 수 있다.
-
PC Register - Register Base가 아닌 Stack Base로 동작하고, 각 Thread 별로 하나씩 PC Register가 존재한다. 그리고 현재 수행중인 Java Virtual Machine Instruction 주소를 가지게 된다.
Instruction의 주소는 Native Pointer일 수도 있고 Method ByteCode일 수 있는데, Native Method를 실행할 떄에는 JVM을 거치지 않고 바로 API를 통해 수행할 수 있다.
Native Method: 해당 OS 환경에서 제공하는 메서드? 다른 언어로 작성된 메서드?
-
JVM Stack: Thread의 수행정보를 Frame을 통해서 저장한다. Thread가 시작될 때 생성되고, 다른 Thread가 접근할 수 없다. Method가 호출되면 Method와 Method 정보가 Stack에 쌓이고, 호출이 종료되면 Stack point에서 제거.
각 스택 프레임은 Local Variable Array, Operand Stack, 현재 실행 중인 메서드가 속한 클래스의 Runtime Constant Pool에 대한 레퍼런스를 가짐.
- Local Variable Array(지역변수 배열) : 0부터 시작하는 인덱스를 가진 배열. 0은 메서드가 속한 클래스 인스턴스의 this 레퍼런스이고, 1부터는 메서드에 전달된 파라미터들이 저장되며, 메서드 파라미터 이후에는 메서드의 지역 변수들이 저장된다.
- Operand Stack(피연산자 스택) : 메서드의 실제 작업 공간. 각 메서드는 피연산자 스택과 지역 변수 배열 사이에서 데이터를 교환하고, 다른 메서드 호출 결과를 push하거나 pop한다. 피연산자 스택 공간이 얼마나 필요한지는 컴파일할 때 결정할 수 있으므로, 피연산자 스택의 크기도 컴파일 시에 결정된다.
-
Native Method Stack
자바 외의 언어로 작성된 네이티브 코드를 위한 스택. JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택. 이렇게 공간을 분리하여 기존의 JVM 내부에 영향을 주지 않는다.
-
Heap
인스턴스(객체)를 저장하는 공간. GC(Garbage Collection)의 대상이다. 성능 이슈를 일으키는 공간
-
Method Area
JVM이 읽어들인 각각의 클래스와 인터페이스에 대한 Runtime Constant Pool. 필드와 메서드 정보, Static 변수, 메서드의 바이트 코드를 보관한다. 이 영역의 정보를 바탕으로 Heap 영역에 객체를 생성한다.
→ 이 영역은 JVM 벤더마다 다양한 형태로 구현할 수 있다. 그리고 이에 대한 가비지 컬렉션은 JVM 벤더의 선택사항.
- Runtime Constant Pool: 클래스 파일 포맷에서 constant_pool table에 해당하는 영역. 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블. 즉, 어떤 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조한다.
간단하게 말하기를,
- Method에 대한 영역은 Method Area,
- 클래스에 대한 영역은 JVM Stack
- Instance에 대한 영역은 Heap
이 된다.
Execution Engine
클래스 로더를 통해 JVM 내의 Runtime Data Area에 배치된 바이트 코드를 실행하는 주체. 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.