![JVM(Java Virtual Machine) 구조](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblPR3s%2FbtsJeV2fAIu%2FVAkC4qNgKEmrRSmML3QHH1%2Fimg.png)
JVM(Java Virtual Machine) 구조legacy/Java2024. 8. 25. 15:43
Table of Contents
자바의 특징
Write once, run anywhere. (한 번 작성하면 어디서든 실행된다.)
1. JVM: Java Virtual Machine
JVM이란 Java 프로그램을 실행하는 가상 환경이다. 자바 가상 머신을 사용하여 자바 바이트 코드를 실행할 수 있다. JVM은 운영체제 위에서 작동하면서, 자바 컴파일러에 의해 생성된 바이트 코드를 운영체제가 이해할 수 있는 기계어로 바꿔 실행한다. 덕분에 자바 프로그램은 특정 운영체제에 종속되지 않고, 다양한 운영체제에서 동일하게 사용할 수 있다.
ex) 소스 코드가 담긴 Person.java 파일이 자바 컴파일러에 의해 컴파일되면 Person.class 파일이 생성된다. 이 .class 파일에는 바이트코드가 포함되어 있고, JVM이 바이트코드를 기계어로 변환하여 실행한다.
1-1. JVM 구조
- 클래스 로더 (Class Loader)
- 자바 컴파일러(javac)에 의해 생성된 .class 파일을 JVM 메모리 영역인 Runetime Data Area으로 로드한다. 클래스 로더는 로딩 → 링크 → 초기화 순으로 진행된다.
- 로딩(Loading) : 클래스 로더는 .class 파일의 바이트코드를 읽어 JVM의 메모리 영역인 Method Area에 저장한다. Method Area에는 클래스의 메타데이터가 저장된다.
- 링킹(Linking) : 로드된 클래스가 실제로 실행 가능한 상태로 준비되기 위해 수행되는 작업이다.
- 검증(Verify) : .class 파일이 손상되지 않았는지 확인한다.
- 준비(Prepare) : 클래스의 static 변수에 메모리를 할당하고 기본 값으로 초기화한다. → 실제 값을 할당하는 게 아닌 기본값으로 초기화된다.
- 해결(Resolve) : 심볼릭 참조를 실제 참조로 변환하는 과정이다.
- ex) Foo foo = new Foo() 에서 foo라는 참조 변수가 힙에 저장된 실제 Foo 인스턴스를 가리킬 수 있도록 한다.
- 초기화(Initialization) : static 변수에 명시적으로 지정된 초기값을 할당하고, static 초기화 블록을 실행한다.
- 자바 컴파일러(javac)에 의해 생성된 .class 파일을 JVM 메모리 영역인 Runetime Data Area으로 로드한다. 클래스 로더는 로딩 → 링크 → 초기화 순으로 진행된다.
- 실행 엔진 (Execution Engine)
- 바이트코드 ****해석 : Class Loader에 의해 JVM 메모리 영역(Runtime Data Area)으로 적재된 클래스 파일(.class, 바이트 코드로 이루어진 파일)을 기계어로 변환하여 프로그램을 실행한다.
- 구성 요소
- JIT 컴파일러 (Just-In-Time Compiler) : 프로그램이 실행되는 과정에서 반복적으로 사용되는 바이트 코드를 기계어로 변환하여 캐싱해 둔다. 이 캐싱된 기계어는 필요할 때 바로 사용되기 때문에 매번 같은 바이트 코드를 해석하는 비용을 줄일 수 있다.
- 인터프리터 (Interpreter) : 바이트 코드를 한 줄씩 순차적으로 읽고 즉시 실행한다. 이 과정에서 바이트코드는 기계어로 변환되지 않고 바이트 코드를 직접 해석하고 실행한다. 이는 같은 코드(반복문 코드)가 반복될 때마다 매번 같은 바이트코드를 해석하고 실행해야 하므로, 반복적으로 실행되는 코드의 경우 효율이 떨어질 수 있다.
- Garbage Collector
- Heap ****영역에 생성된 객체 중 더 이상 참조되지 않는, 즉 프로그램에서 사용되지 않는 객체들을 식별하고 제거하는 역할을 한다. 이를 통해 메모리 누수를 방지하고 사용 가능한 메모리를 확보하여 프로그램이 효율적으로 실행될 수 있도록 한다.
- 자바는 명시적으로 메모리 해제를 하지 않고 GC가 메모리 관리를 자동으로 수행한다.
- JVM 메모리 영역 (Runtime Data Area)
- 자바 프로그램이 실행되는 동안 JVM 내부에서 사용하는 메모리 영역이다.
- 메서드 영역 (Method Area)
- 클래스 구조(필드, 메서드, 인터페이스 등) 정보, 메서드 구조(메서드 이름, 리턴 타입, 파라미터, 접근 제어자), 상수 풀(Constant Pool), 정벅 변수(static) 등이 저장된다.
- 힙 영역 (Heap Area)
- 객체와 배열이 동적으로 할당되는 공간이다. 모든 자바 객체는 Heap에 저장되며, 이 영역은 GC에 의해 관리된다.
- 스택 영역 (Stack Area)
- 각 스레드별로 할당받는 메모리 영역으로, 메서드 호출 시 생성되는 스택 프레임이 저장된다. 이 스택 프레임에는 지역 변수, 파라미터, 메서드의 리턴 주소 등이 포함된다.
- PC 레지스터
- 현재 실행 중인 명령어의 주소를 저장한다. JVM은 자바 바이트코드를 실행할 때 어느 명령어를 실행하고 있는지 추적하기 위해 사용된다.
- Native Method Stack
- 자바가 아닌 네이티브 코드(C, C++)를 실행할 때 사용되는 스택이다. 자바 프로그램이 JVM 외부에서 동작하는 코드(주로 운영체제 레벨의 코드)를 호출할 때 사용하는 메모리 영역이다.
2. JVM의 장점
- 이식성 : JVM이라는 가상 머신이 운영체제 위에서 작동하기 때문에 자바 언어로 작성한 프로그램이 플랫폼의 제한을 받지 않는다. 자바로 작성한 프로그램이 운영체제의 종류와 상관없이 가상머신에서 작동하기 때문에 이식성이 높다.
- 메모리 관리 : JVM은 GC에 의해 참조되지 않는 객체를 자동으로 정리한다. 개발자는 명시적으로 메모리 해제를 할 필요 없이 자동으로 GC가 해제하므로 메무리 누수를 방지할 수 있다.
3. JVM의 단점
- 실행 속도 : JVM은 바이트코드를 실행 중에 기계어(이진 코드, CPU가 실행할 수 있는)로 변환하여 운영체제가 실행할 수 있도록 하기 때문에, 다른 언어에 비해 초기 실행 속도가 느릴 수 있다.
- 바이트코드 생성 : 자바 소스 코드는 컴파일러(javac)에 의해 바이트 코드로 변환되어 .class 파일로 생성된다. 이 바이트 코드는 자바 프로그램이 운영체제의 종류에 상관없이 실행될 수 있도록 설계된 코드이다.
- 바이트 코드를 기계어로 변환 : JVM은 운영체제 위에서 동작하며 컴파일된 바이트 코드를 실행 중에 해당 운영체제에 맞는 기계어로 변환한다. 이 변환 작업은 JIT 컴파일러에 의해 실행 중에 필요할 때 이루어지는데, 이 과정이 초기 실행 시간에 영향을 미친다.
- 운영체제가 기계어를 실행 : JVM이 바이트 코드를 기계어로 변환하면 운영체제는 변환된 기계어를 CPU가 직접 사용할 수 있도록 한다.
- 메모리 사용량 : JVM은 프로그램 실행 시 상당향 양의 메모리를 사용한다. JVM 자체가 메모리를 차지할 뿐만 아니라 프로그램 실행 시 필요한 클래스 로딩과 객체 생성을 위해 추가적인 메모리가 필요하다. JVM은 초기 실행 시점에 많은 메모리를 미리 할당하므로 초반 메모리 사용량이 높다.
참고
https://ko.wikipedia.org/wiki/JIT_컴파일
https://jeong-pro.tistory.com/148