JVM(Java Virtual Machine)은 Java 프로그램을 수정 없이 모든 플랫폼에서 실행할 수 있도록 하는 JRE(Java Runtime Environment)의 핵심 구성 요소입니다. JVM은 Java 바이트코드와 Java의 유명한 WORA(Write Once Run Anywhere) 기능을 제공하는 기본 하드웨어 간의 인터프리터 역할을 합니다.
- Java 소스(.java) -> javac로 컴파일됨 -> 바이트코드(.class)
- JVM은 바이트코드를 로드하고 링크를 확인한 후 실행합니다.
- 실행에는 바이트코드를 해석하거나 JIT(Just-In-Time) 컴파일을 사용하여 성능을 위해 핫 코드를 기본 기계어 코드로 변환하는 작업이 포함될 수 있습니다.
- 가비지 수집은 사용하지 않는 객체에서 메모리를 회수하기 위해 백그라운드에서 실행됩니다.
JVM의 아키텍처
아래 이미지는 JVM의 아키텍처와 주요 구성 요소를 보여줍니다.
JVM 아키텍처의 구성 요소
이제 JVM의 각 구성 요소에 대해 자세히 설명하겠습니다.
1. 클래스 로더 서브시스템
크게 3가지 활동을 담당합니다.
1. 로딩
- .class 파일을 읽고 메서드 영역에 클래스 메타데이터를 저장합니다.
- 로드된 클래스를 나타내는 힙에 Class 개체를 만듭니다.
class GFG{ static{ System.out.println('GFG class is loaded by the JVM!'); } public void display(){ System.out.println('Method of GFG class is executed.'); } } public class Test{ public static void main(String[] args) throws Exception{ System.out.println('Main method started.'); // Loading the class explicitly using Class.forName() Class.forName('GFG'); System.out.println('Class loaded successfully.'); // Creating object to execute method GFG obj = new GFG(); obj.display(); } }
산출
Main method started. GFG class is loaded by the JVM! Class loaded successfully. Method of GFG class is executed.
메모: 로드된 모든 항목에 대해 .수업 파일만 하나 클래스의 객체가 생성됩니다.
2. 연결: 실행을 위해 로드된 클래스를 준비하는 일을 담당합니다. 여기에는 세 가지 단계가 포함됩니다.
- 확인: 바이트코드가 JVM 규칙을 따르고 실행하기에 안전한지 확인합니다.
- 준비: 정적 변수에 메모리를 할당하고 기본값을 할당합니다.
- 해결: 기호 참조를 메모리의 직접 참조로 변환합니다.
3. 초기화
- 정적 변수에 실제 값을 할당합니다.
- 클래스에 정의된 정적 블록을 실행합니다.
클래스 로더 유형
- 부트스트랩 클래스 로더: 핵심 Java 클래스(JAVA_HOME/lib)를 로드합니다.
- 확장 클래스 로더: 확장 디렉토리(JAVA_HOME/jre/lib/ext)에서 클래스를 로드합니다.
- 시스템/애플리케이션 클래스 로더: 애플리케이션 클래스 경로에서 클래스를 로드합니다.
// Java code to demonstrate Class Loader subsystem public class Geeks { public static void main(String[] args) { // String class is loaded by bootstrap loader and // bootstrap loader is not Java object hence null System.out.println(String.class.getClassLoader()); // Test class is loaded by Application loader System.out.println(Geeks.class.getClassLoader()); } }
산출
null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
2. JVM 메모리 영역
- 방법 영역: 클래스 이름 상위 클래스 메서드 변수 및 정적 데이터와 같은 클래스 수준 정보를 저장합니다. JVM 전체에서 공유됩니다.
- 힙 영역: 모든 객체를 저장합니다. JVM 전체에서 공유됩니다.
- 스택 영역: 각 스레드에는 자체 런타임 스택이 있습니다. 메소드 호출 지역 변수를 스택 프레임에 저장합니다. 스레드가 끝나면 삭제됩니다.
- PC 레지스터: 각 스레드에 대해 현재 실행 중인 명령어의 주소를 보유합니다.
- 네이티브 메서드 스택: 각 스레드에는 기본 메서드 실행을 위한 별도의 스택이 있습니다.
3. 실행 엔진
실행 엔진은 .class(바이트코드)를 실행합니다. 바이트코드를 한 줄씩 읽어 각종 메모리 영역에 존재하는 데이터와 정보를 이용하여 명령어를 실행한다. 이는 세 부분으로 분류될 수 있습니다:
- 통역사: 바이트코드를 한 줄씩 해석한 다음 실행합니다. 여기서 단점은 하나의 메서드를 여러 번 호출할 때마다 해석이 필요하다는 점입니다.
- JIT(Just-In-Time 컴파일러): 통역사의 효율성을 높이기 위해 사용됩니다. 전체 바이트코드를 컴파일하고 네이티브 코드로 변경하므로 인터프리터가 반복적인 메서드 호출을 볼 때마다 JIT는 해당 부분에 대한 직접 네이티브 코드를 제공하므로 재해석이 필요하지 않으므로 효율성이 향상됩니다.
- 가비지 컬렉터: 참조되지 않은 객체를 파괴합니다. 가비지 수집기에 대한 자세한 내용은 다음을 참조하세요. 가비지 컬렉터 .
4. 자바 네이티브 인터페이스(JNI)
Native Method Libraries와 상호작용하고, 실행에 필요한 네이티브 라이브러리(C C++)를 제공하는 인터페이스입니다. 이를 통해 JVM은 C/C++ 라이브러리를 호출하고 하드웨어에 특정한 C/C++ 라이브러리에 의해 호출될 수 있습니다.
5. 네이티브 메소드 라이브러리
네이티브 메서드를 실행하는 데 필요한 네이티브 라이브러리 모음입니다. 여기에는 C 및 C++와 같은 언어로 작성된 라이브러리가 포함됩니다.