JVM(Java Virtual Machine)
- 자바 프로그램 실행환경을 만들어 주는 소프트웨어이다. 모든 자바 애플리케이션은 JVM 위에서 실행되며, 이러한 특성은 자바가 "Write Once, Run Anywhere(WORA)"라고 불리는 특징을 구현하는 데 기여한다.
- 자바 언어와 JVM의 관계 : 자바 언어로 작성된 프로그램은 컴파일러를 통해 바이트 코드(bytecode)라는 중간 형식으로 변환된다. 이 바이트 코드는 특정 운영 체제나 아키텍처에 의존하지 않으며, 이로써 자바 프로그램은 어떤 환경에서도 실행될 수 있다.
- 운영 체제 독립성 : JVM은 특정 OS에 맞게 자바 바이트 코드를 해석하고 실행한다. 따라서 자바 프로그램은 운영 체제에 독립적이며, 자바 개발자는 프로그램을 한 번 작성하면 다양한 운영체제에서 실행할 수 있다. (단, JVM은 운영체제에 종속적이다.)
- 언어 다양성 : JVM은 자바 뿐만 아니라 코틀린, 스칼라 등의 다른 언어로 작성된 프로그램도 실행할 수 있다.
- 성능 : 이전에는 JVM이 애플리케이션의 실행 속도를 느리게 만들 수 있다는 주장도 있었지만, 현대의 JVM은 JIT(Just-In-Time) 컴파일러와 최적화 기술을 사용하여 성능 문제를 크게 완화시켰다.
JVM 구성요소
클래스 로더가 컴파일도니 자바 바이트코드를 런타임 데이터 영역에 로드하고, 실행 엔진이 자바 바이트코드를 실행한다.
1. 클래스 로더(Class Loader)
자바의 특징 중 하나인 "동적 로드(Dynamic Loading)"를 담당한다. 동적 로드란, 자바 클래스가 컴파일 타임이 아니라 런타임에서 필요한 순간에 로드되고 링크되는 것을 의미한다.
클래스 로더들은 부모-자식 관계를 혈성하여 계층 구조를 형성한다. 이 계층 구조는 다음과 같이 구성된다.
- 부트스트랩 클래스 로더(Bootstrap Class Loader)
JVM을 시작할 때 가장 먼저 생성되며, 자바의 핵심 API와 Object 클래스 같은 핵심 클래스들을 로드한다. 네이티브 코드로 구현되어 있다. - 익스텐션 클래스 로더(Extension Class Loader)
기본 자바 API를 제외한 확장 클래스들을 로드한다. 보안 확장 및 기타 확장 기능을 여기에서 로드한다. - 시스템 클래스 로더(System Class Loader)
애플리케이션 클래스들을 로드하는 역할을 한다. 사용자가 지정한 클래스 패스($CLASSPATH)내의 클래스들을 로드한다. - 사용자 정의 클래스 로더(User-Defined Class Loader)
사용자가 직접 생성하여 사용하는 클래스 로더로, 애플리케이션의 클래스를 독립적으로 로드하도록 도와준다.
클래스 로드 과정
- 로드(Loading) : 클래스를 파일에서 가져와서 JVM 메모리에 로드
- 검증(Verifying) : 로드한 클래스가 자바 언어와 JVM 명세에 맞게 잘 구성되어 있는지 검사. 클래스 로드 과정에서 가장 복잡하고 시간이 많이 걸린다.
- 준비(Preparing) : 클래스가 필요로 하는 메모리를 할당하고, 클래스에서 정의된 필드, 메서드, 인터페이스 등을 나타내는 데이터 구조 준
- 분석(Resolving) : 클래스 내의 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경. 이 과정을 통해 클래스나 멤버의 심볼릭 레퍼런스가 실제로 어떤 클래스나 멤버를 가리키는지 연결된다.
- 초기화(Initializing) : 클래스 변수들을 초기화하고, static initializer를 실행하여 static 필드들을 설정된 값으로 초기화하고 클래스를 사용 가능한 상태로 만든다.
심볼릭 레퍼런스(Symbolic Reference)
- 클래스나 필드, 메서드와 같은 멤버에 대한 참조를 나타낸다.
- 구체적인 메모리 주소나 위치를 가리키지 않고, 멤버의 이름과 타입 등의 정보만을 포함하고 있다.
다이렉트 레퍼런스(Direct Reference)
- 실제로 클래스나 멤버에 대한 참조를 가리킨다.
2. 런타임 데이터 영역(Runtime Data Area)
런타임 데이터 영역은 JVM의 실행 중에 할당되고 사용되는 메모리 영역을 나타낸다. 6개의 영역으로 나눌 수 있는데 이중 PC 레지스터, JVM 스택, 네이티브 메서드 스택은 스레드마다 하나씩 생성되며, 힙, 메서드 영역, 런타임 상수 풀은 모든 스레드가 공유해서 사용한다.
- PC 레지스터(Program Counter Register)
- 스레드가 시작될 때 생성된다.
- 현재 수행 중인 JVM 명령어의 주소를 가지고 있으며, 스레드가 명령어를 실행할 다음 위치를 가리킨다.
- JVM 스택(JVM Stack)
- 스레드가 시작될 때 생성된다.
- 스택 프레임(Stack Frame)이라는 구조체를 저장하는 스택으로, 메서드 호출과 관련된 정보를 저장한다.
- 지역 변수 배열(Local Variable Array)과 피연산자 스택(Operand Stack), 현재 실행 중인 메서드가 속한 클래스의 런타임 상수 풀 포함하여, 메서드 호출 및 반환에 관한 데이터를 관리한다.
- 네이티브 메서드 스택(Native Method Stack)
- 자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다.
- JNI(Java Native Interface)를 통해 호출되는 C/C++ 등의 코드를 실행하기 위한 공간이다.
- 힙(Heap)
- 인스턴스가 객체를 저장하는 공간이다.
- 자바 객체가 생성되고 메모리를 할당하는 곳으로, 자바 프로그램의 데이터를 저장한다.
- JVM 성능 및 가비지 컬렉션과 관련된 영역이다.
- 메서드 영역(Method Area)
- JVM이 시작될 때 생성된다.
- 클래스와 인터페이스 정보, 펀타임 상수 풀, 필드와 메서드 정보, static 변수, 메서드의 바이트코드 등을 저장한다.
- JVM 벤더마다 다양한 형태로 구현될 수 있다.
- 런타임 상수 풀(Runtime Constant Pool)
- 클래스 파일 포맷의 constant_pool 테이블에 해당하는 영역으로 메서드 영역에 포함된다.
- 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 레퍼런스까지 담고 있는 테이블이다.
- 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 사용한다.
3. 실행 엔진(Exceution Engine)
실행 엔진은 JVM 내에서 자바 바이트코드를 실제로 실행하는 역할을 한다. 바이트코드는 기계가 이해할 수 없는 코드이기 때문에 이것을 기계가 실행할 수 있는 코드로 변환하는데 이때, 실행 엔진은 두 가지 방식으로 동작한다.
1. 인터프리터(Interpreter)
- 자바 바이트코드를 명령어 단위로 읽고 해석하여 실행한다.
- 각 바이트코드 명령어는 1바이트 크기의 OpCode와 필요한 피연산자로 이루어져 있다.
- 인터프리터는 바이트코드를 하나씩 해석하고 실행하기 때문에 실행 속도가 느릴 수 있으나, JVM을 구동하는 데 별도의 컴파일 단계가 필요 없어서 플랫폼 독립성을 제공한다.
2. JIT(Just-In-Time) 컴파일러
- 인터프리터의 성능 단점을 극복하기 위해 도입된 기술이다.
- 인터프리터 방식으로 실행하다가 일정한 조건이 충족되면 해당 바이트코드를 네이티브 기계 코드로 컴파일한다.
- 네이티브 코드는 컴퓨터의 CPU에서 직접 실행할 수 있으며, 인터프리터보다 빠르게 동작한다.
- JIT 컴파일러는 바이트코드를 런타임에 컴파일하므로, 실행 중에 최적화 기회가 제공되어 성능을 향상시킬 수 있다.
- 컴파일된 코드는 캐시에 저장되어 이후에 동일한 코드가 다시 실행될 때 재사용된다.
일반적으로 한 번만 실행되는 코드는 인터프리터로 실행하고, 자주 실행되는 코드 블록(핫스팟 코드)은 JIT 컴파일러를 통해 네이티브 코드로 변환한다.
JVM 실행 과정
- 프로그램이 실행되면, JVM은 OS로부터 해당 프로그램이 필요로 하는 메모리를 할당받는다.
- 자바 소스 코드를 컴파일러(JAVAC)를 통해 자바 바이트코드(.class파일)로 변환한다.
- 변환된 클래스 파일들은 클래스 로더를 통해 JVM의 메모리 영역으로 로딩된다. 이때, 클래스의 정보와 코드 등이 메모리에 저장된다.
- 실행 엔진이 로딩된 클래스 파일을 해석하고, 바이트코드를 메모리 영역에 배치하여 프로그램을 실행한다.
- 프로그램 실행 중에 메모리 관리, 스레드 관리를 수행한다.
[참고] https://d2.naver.com/helloworld/1230
https://gyoogle.dev/blog/computer-language/Java/Java%20Virtual%20Machine.html
'Languages > Java' 카테고리의 다른 글
[Java] Error & Exception (0) | 2023.09.07 |
---|---|
[Java] Garbage Collection (0) | 2023.09.06 |
[Java] 고유 락 (Intrinsic Lock) (0) | 2023.08.31 |
[Java] 스레드 (Thread) (0) | 2023.08.31 |
[Java] Casting (0) | 2023.08.10 |