JVM이란?
JVM은 (Java Virtual Machine) 자바 가상 머신의 약자로 자바 프로그램 런타임 환경을 제공하는 소프트웨어이다. 자바 애플리케이션을 클래스 로더를 통해 읽어 들여, 자바 API와 함께 실행하는 역할을 한다. Java와 OS 사이에서 중개자 역할을 수행해 Java가 OS에 구애받지 않고 실행되도록 한다. 또한, Garbage Collection을 통해 프로그램 메모리 관리와 최적화를 수행한다.
JVM의 구조
Class Loader
클래스 로더는 class 파일을 JVM의 메모리 영역인 Runtime Data Area로 로딩, 검증, static 변수를 초기화하는 등의 역할을 한다.
Execution Engine
클래스 코드는 기계가 바로 수행할 수 있는 형태로 기술되어 있지 않다. 그렇기 때문에 실행 엔진은 이 바이트 코드를 기계어로 변환하는 일을 한다. 이때 2가지 방식을 이용한다.
Interpreter
Interpreter는 바이트 코드 명령어를 하나씩 읽어서 해석하고 실행하는 방식으로 전체적인 실행 속도가 느리다는 단점이 있다.
JIT Compiler
JIT(Just-In-Time) Compiler는 인터프리터의 단점을 보완하기 위해 도입되었다. 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일해 Native Code(특정 플랫폼에서 직접 실행 가능한 기계어 코드)로 변경하고, 이후에는 더 이상 인터프리팅하지 않고 Native Code로 직접 실행하는 방식이다. 이러한 방식은 처음에는 컴파일 시간이 추가되지만, 한 번 컴파일된 코드는 캐시에 저장되어 성능 향상을 가져온다. JVM은 JIT 컴파일러를 통해 일부 코드만 변경되면 해당 부분만 재컴파일하고, 나머지는 캐싱된 코드를 재사용함으로써 빠르게 수행될 수 있다. 바이트 코드를 Native Code로 변환하는 데에는 비용이 소요되므로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정 기준을 넘어가면 JIT 컴파일 방식으로 명령어를 실행한다.
Garbage Collector
JVM은 가비지 컬렉터(Garbage Collector)를 이용해 더는 사용하지 않는 메모리를 자동으로 회수한다. Heap 메모리 영역에 생성(적재)된 객체들 중에 참조되지 않은 객체들을 탐색 후 제거하는 역할을 한다. GC역할을 수행하는 스레드를 제외한 나머지 모든 스레드들은 일시 정지 상태가 된다.
Runtime Data Area
Method Area
클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 필드 정보들과 메서드 정보 등 클래스에 대한 모든 정보가 저장된다.
Heap
런타임에 생성되는 모든 객체들이 저장된다.
Stacks Area
메소드를 실행하기 위한 영역으로 JVM 스레드가 생겨날 때 해당 스레드를 위한 스택도 함께 만들어진다. 각각의 메서드 호출은 스택에서 하나의 프레임(Frame)으로 표현되며, 프레임은 해당 메서드 호출에 필요한 데이터와 제어 정보를 담고 있다.
프레임은 3가지 구성 요소를 갖는다.
- Local Variables Array: 메소드 내에서 선언된 변수들이 저장된다.
- Operand Stack: 연산에 필요한 임시 값들이 저장된다.
- Frame Data: 프레임의 제어 정보 및 메소드 호출 시 반환 주소, 호출된 메소드의 정보와 메서드의 실행 중인 위치, 호출한 메서드로부터 돌아갈 위치 등이 저장된다.
PC Registers
현재 수행 중인 명령어의 위치, 즉 다음에 실행될 바이트코드의 주소를 가리킨다. JVM은 이 PC 레지스터를 사용하여 명령어의 실행 위치를 추적하고, 각 스레드가 실행되는 동안 프로그램 카운터 값을 업데이트하여 다음에 수행될 명령어를 지정한다.
PC 레지스터는 스레드마다 별도로 관리되며, 스레드가 새로운 명령어를 수행할 때마다 해당 스레드의 PC 레지스터가 업데이트된다. 이를 통해 JVM은 다수의 스레드가 병렬로 실행될 때도 각각의 스레드에 대한 프로그램 카운터를 독립적으로 추적할 수 있다.
Native Method Stack
Java 언어 외부에서 작성된 네이티브 코드(C 또는 C++로 작성된 코드)를 호출할 때 사용되는 스택이다. 각각의 스레드가 네이티브 코드를 실행하는 데 필요한 정보를 저장한다.
Method와 Heap 영역은 모든 쓰레드가 공유하는 영역이기 때문에 멀티스레드 프로그래밍을 할 때 동기화에 주의해야 하며 Stacks Area, PC Registers, Native Method Stack은 스레드가 생성될 때 마다 함께 생성되는 영역으로 서로 다른 스레드가 침범할 수 없는 영역이다.
'JVM' 카테고리의 다른 글
StringBuffer vs StringBuilder (0) | 2024.07.22 |
---|---|
java.security.invalidKeyException: Illegal Key Size (0) | 2024.05.04 |
자바 내부 클래스(Inner Classes) (0) | 2024.03.01 |
쓰레드 동기화 (0) | 2024.03.01 |
Google JIB (0) | 2024.01.30 |