JVM의 동작 방식 및 구조
- 자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당받는다.
- 자바 컴파일러(Javac)가 자바 소스코드(. java)를 자바 바이트 코드(. class)로 컴파일한다.
- Class Loader는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크하여 Runtime Data Area에 올린다.
- Runtime Data Area에 로딩된 바이트 코드는 Execution Engine을 통해 해석된다.
- 이 과정에서 Execution Engine에 의해 Garbage Collector의 작동과 Thread 동기화가 이루어진다.
💡Runtime Data Area는 실직적인 메모리를 할당받아 관리하는 영역.
JVM의 역할은 Java 애플리케이션을 클래스 로더를 통해 읽어 Java API와 함께 실행하는 것을 알 수 있다.
위 JVM의 동작 과정을 더 상세하게 도식화하면 아래와 같다.
Class Loader
- 소스코드(.java)를 컴파일 해서 얻은 바이트 코드(.class)들을 동적으로 JVM의 메모리 영역에 배치하는 작업을 수행하는 모듈
- 클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고 애플리케이션에서 필요한 경우 동적으로 메모리에 적재하게 된다.
- 로드할 클래스가 여럿인 경우 Main() 메소드를 포함하는 클래스를 우선 로드한다.
Class Loader 동작 순서
- Loading(로드) : 클래스 파일을 가져와서 JVM의 메모리에 로드한다.
- Linking(링크) : 클래스 파일을 사용하기 위해 검증하는 과정
- Initializing(초기화) : 클래스 변수들을 적절한 값으로 초기화하는 과정.
로딩(Loading)
💡 클래스를 읽어오는 과정
- 클래스 로더가 .class 파일을 읽고, 내용에 맞는 binary 데이터를 생성한 뒤, 메모리의 Method 영역에 저장한다.
- 클래스가 속한 패키지명을 모두 포함한 이름
- 클래스, 인터페이스, Enum
- 각 클래스/인터페이스의 메서드, 변수
- 로딩이 완료되면, 해당 클래스 타입의 class 객체를 생성해 Heap영역에 저장한다.
- 객체이름.class 또는 인스턴스의 getClass() 형태로 호출했을 때 리턴되는 값을 말함.
- Class<객체이름> 형태
1. Bootstrap Class Loader
- java.lang, java.net, java.util, java.io와 같은 표준 Java 패키지 로드
- rt.jar 파일에 들어있는 핵심 라이브러리
2. Extension Class Loader (확장)
- 확장 라이브러리 클래스 로드
3. Application Class Loader (응용 프로그램)
- 일반적으로 개발자가 작성한 코드를 포함한 클래스 로드
- (-classpath, -cp) 클래스 경로에 있는 클래스 로드
- 로더가 클래스 이름을 찾지 못할 경우, NoClassDefFoundError, ClassNotFoundExeception 발생
💡개발에 필요한 기본적인 라이브러리(Bootstrap, Extension)들이 먼저 로딩된 후, 개발자가 작성한 클래스가 로딩된다.
링크(Linking)
💡 클래스 파일을 로드한 후 수행되는 과정으로 클래스 간 의존 관계를 분석하고 함께 링크한다.
- Verifying(검증)
- 클래스 파일을 로드한 후, 그 파일의 유효성, 안정성을 검증하는 단계.
- 클래스 파일의 내용이 Java 언어 규칙을 따르는지, JVM의 규칙에 따라 올바른 지 확인한다.
- 해당 단계를 통해 프로그램 실행 중 발생할 수 있는 잠재적인 문제를 사전에 방지한다.
- 바이트 코드가 조작될 경우, JVM 에러가 발생한다.
- Preparing(준비)
- 클래스 파일의 유효성을 확인한 후, JVM은 클래스의 정적 필드(Static)에 필요한 메모리를 할당하고 기본 값으로 초기화 한다.(생성자 호출 전일 경우 0으로 초기화)
- ex) static boolean test = true; 가 있다고 치면 해당 과정에서 초기화는 false로 되는 것이 아닌 메모리 할당을 위한 초기화이기 때문에 일단 0으로 초기화 후 초기화 단계에서 실제 값으로 초기화한다.
- 해당 단계에서는 정적 필드에 대한 메모리를 할당하는 것만 포함되며, 인스턴스 변수, 초기화는 포함되지 않는다.
- 클래스 파일의 유효성을 확인한 후, JVM은 클래스의 정적 필드(Static)에 필요한 메모리를 할당하고 기본 값으로 초기화 한다.(생성자 호출 전일 경우 0으로 초기화)
- Resolving(분석)
- 로드된 클래스가 참조하는 다른 클래스/인터페이스를 확인하여, 클래스 간의 상호 의존성을 해결한다.
- 클래스 파일 안에서 사용되는 심볼(변수, 메서드, 클래스 이름 등)을 실제 메모리상의 주소나 위치와 연결하며 클래스의 상속 관계와 인터페이스 구현을 설정한다.
Snack s = new Snack("포카칩", 2);
// 위 코드에서 s라는 참조변수가 Heap에 저장된 실제 Snack 클래스를 가리킬 수 있도록 연결하는 과정.
초기화 (Initialization)
💡 클래스/ 인터페이스의 정적 변수, 정적 메서드를 초기화하는 단계.
- 클래스 생성자 호출
- 정적 필드에 0이 아닌 초깃값을 기술할 경우 실제 값으로 초기화되며, 선언된 순서대로 초기화된다.
- 정적 초기화는 한 번만 수행되며, 클래스가 처음으로 로드될 대만 실행된다. 그 후 같은 클래스가 다시 로드되더라도 정적 초기화하는 실행되지 않는다.
- 멀티스레드 환경을 고려하지 않을 경우 클래스 초기화 중 오류발생 가능성이 있다.
- 💡생성자에서는 멀티 스레드 관련된 동기화가 요구되는 코드를 작성해서는 안된다
실행 엔진(Execution Engine)
Execution Engine은 로드된 클래스 파일의 바이트 코드를 실행하는 엔진으로 바이트 코드를 실행하기 위해서는 컴퓨터가 이해할 수 있도록 기계어로 변환하는 작업이 필요하다. 이러한 수행 작업은 Interpreter와 JIT 컴파일러 두 가지 방식을 혼합하여 실행한다.
해석 작업
- Interpreter
- 명령어를 한줄씩 해석하며 실행하며 JVM안에서 바이트 코드는 기본적으로 Interpreter 방식으로 동작한다.
- 같은 메서드라도 여러번 호출 시, 매번 해석하고 수행해야 하므로 전체적으로 속도가 느리다.
- JIT 컴파일러(성능 향상이 목적)
- Interpreter의 단점을 해결하기 위한 방법으로 반복되는 코드를 발견하여 바이트 코드 전체를 컴파일 하여 Native Code로 변경하고 이후에는 해당 메서드를 더 이상 인터프리팅 하지 않고 캐싱해 두었다가 Native Code로 직접 실행하는 방식
- 하나씩 실행하는 것이 아니라 컴파일 된 Native Code를 실행하기 때문에 전제적인 속도는 Interpreter 방식보다 빠르다.
다만, 바이트 코드를 Native Code로 변환하는 방식에도 비용이 소요되므로 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고 Interpreter 방식을 사용하다 일정 기준을 넘어가면 JIT 컴파일러 방식으로 명령어를 실행하는 식으로 진행한다.
💡Native Code : C/C++, 어셈블리어로 구성된 코드
기계어로 변환(해석)된 코드는 Runtime Data Area에 배치되어 스레드 동기화나 GC을 수행한다.
JNI (Java Native Interface)
- Java가 다른 언어로 만들어진 애플리케이션과 상호작용할 수 있는 인터페이스를 제공하는 프로그램.
- JNI는 JVM이 Native Method를 적재하고 수행할 수 있도록 한다.
- 실직적으로 제대로 동작하는 언어는 C/C++ 정도이다.
Native Method Library
- C/C++로 작성된 라이브러리
- JNI가 해당 라이브러리를 통해 로딩하고 실행한다.
Reference.
https://youtu.be/IRLoyKqDXC0?si=FjrGpU2wyJ51S8cr
'Backend > JVM' 카테고리의 다른 글
가비지 컬렉션(Garbage Collection, GC)의 작동 원리 (0) | 2023.09.11 |
---|---|
JVM 힙(Heap) 영역 (0) | 2023.09.08 |
가비지 컬렉션(Garbage Collection, GC)의 개념 (0) | 2023.09.01 |
JVM 동작 방식 및 메모리 구조(1) (0) | 2023.08.30 |
JVM이란? (0) | 2023.08.29 |