JVM(Java Virtual Machine)
자바 가상 머신, 자바 바이트 코드(.class)를 실행하는 프로그램
가상 머신 : 컴퓨터를 에뮬레이션하는 소프트웨어, 가상머신 상에서 운영 체제나 응용 프로그램을 설치 및 실행 가능
- 운영체제 독립적, 자동으로 메모리 관리(GC), 안정적
출처
JVM 역할은 자바 어플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행하는 것이다. JVM은 JAVA와 운영 체제 사이에서 중개자 역할을 수행하여 OS에 구애받지 않고 사용할 수 있다.
그리고 메모리 관리 Garbage Collection 을 수행한다.
JVM은 스택 기반의 가상머신이다.
JAVA 프로그램 실행과정
- 프로그램이 실행되면 JVM은 OS로부터 프로그램이 필요로 하는 메모리를 할당 받는다.
- 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트 코드(.class)로 변환한
다.
- Class Loader를 통해 class 파일을 JVM으로 로딩한다.
- 로딩된 class 파일들은 Execution Engine을 통해 해석된다.
- 해석된 바이트 코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어진다.
이러한 과정 속에서 JVM은 필요에 따라 쓰레드 동기화와 GC 같은 관리 작업을 수행한다.
JVM 구성 요소
- ClassLoader : 클래스 파일들을 Runtime Data Area의 메서드 영역으로 불러오는 역할
- Runtime Data Area : 런타임 시, 클래스 데이터와 같은 메타 데이터와 실제 데이터가 저장되는 곳
- Execution Engine : .class 파일과 같은 바이트 코드를 실행 가능하도록 해석한다.
Class Loader
클래스를 메모리에 올리는 동적 클래스 로딩 기능이 클래스 로더에 의해 이루어진다.
JVM 내로 클래스 파일을 로딩하고, 링크를 통해 배치하는 작업을 수행한다.
자바 클래스들은 한번에 메모리에 올라오는 것이 아니라, 런타임 시 필요할 때 동적으로 클래스를 올라오게 된다.
모든 클래스는 클래스가 참조되는 순간 동적으로 JVM에 링크되며, 메모리에 로딩된다.
클래스 로딩의 3단계
Loading -> Linking -> Initialization
Execution Engine(실행 엔진)
Runtime Data Area에 할당된 자바 바이트 코드를 실행 엔진이 실행시킨다.
바이트 코드를 읽고 한줄씩 실행한다.
클래스 로더가 JVM 내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 그것은 실행 엔진에 의해 실행된다.
실행 엔진은 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경한다.
Interpreter(인터프리터)
실행 엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다. 하지만 한줄씩 수행하기 때문에 느리고, 하나의 메서드를 여러 번 호출할 때, 매번 새로운 해석이 요구된다.
JIT Compiler
인터프리터의 단점을 없앤다. 실행 엔진은 인터프리터가 바이트 코드를 변환하는 데 사용하지만, 반복되는 코드를 발견하면 전체 바이트 코드를 컴파일하고 그것을 native code로 바꾸는 JIT Compiler를 사용한다.
여기서 생성된 native code는 반복되는 메서드 호출에 대해 성능을 개선하기 위해 직접적으로 사용된다.
Garbage Collector(GC)
참조되어 있지 않은 객체들을 모으고 제거하는 역할을 한다.
JVM 메모리 구조
모든 자바 프로그램은 자바 가상 머신(JVM)을 통해 실행된다.
자바 프로그램이 실행되면, JVM은 운영체제로부터 해당 프로그램을 수행할 수 있도록 필요한 메모리를 할당받는다.
메모리는 크게 4가지 영역(코드실행 + static, stack, heap)으로 나눌 수 있다.
static(method) 영역
- 패키지나 클래스 정보가 올라감, 프로그램 시작과 동시에 모두 올라가는 것이 아니라, 실제로 호출될 때 올라가게 됨
- 자바 프로그램에서 사용되는 클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 영역
- static 영역에 있으면 어떤 곳에서나 접근이 가능하기 때문에 "전역"이라는 키워드를 사용
-> static 변수는 읽기 전용이 아닌 경우에는 가능한 사용하지 말아야 함
- JVM은 자바 프로그램에서 특정 클래스가 사용되면 해당 클래스의 클래스 파일(*.class)를 읽어들여, 해당 클래스에 대한 정보를 메서드 영역에 저장
- static 영역에 자리잡게되면 JVM이 종료 될 때까지 사라지지 않고, 고정된(static) 상태로 유지
heap 영역
- 자바 프로그램에서 사용되는 모든 인스턴스 변수가 저장되는 영역(생성된 객체(인스턴스)들)
- JVM은 자바 프로그램에서 new 키워드를 사용하여 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장함
- 메모리의 낮은 주소 👉 높은 주소의 방향으로 할당
- 메서드들은 static이 아니더라도 heap에 생기지 않음. 같은 로직의 메서드이기 때문에 여러개일 필요 X
- 어떤 참조 변수도 힙영역에 있는 인스턴스를 참조하지 않으면, GC(Garbage Collector)에 의해 메모리에서 사라짐 -> 자바는 개발자가 직접 해제해줄 수 없는 언어
Garbage Collector
- Heap 메모리 영역에 생성된 객체 중, 참조되지 않는 객체들을 탐색 후 제거하는 역할
- GC가 수행하는 동안 GC를 수행하는 쓰레드가 아닌 다른 모든 쓰레드가 일시정지됨.
- 상속한 인스턴스를 만들었으면, 상위 클래스의 인스턴스도 함께 생성됨
stack 영역
- 자바 프로그램에서 메서드가 호출될 때 메서드의 스택 프레임이 저장되는 영역
- JVM은 자바 프로그램에서 메서드가 호출되면, 메서드의 호출과 관계되는 지역 변수와 매개 변수를 스택 영역에 저장
- LIFO 방식
- 메모리의 높은 주소 👉 낮은 주소의 방향으로 할당
- 여는 중괄호({)를 만날 때마다 스택 프레임이 하나씩 생기고, 닫는 중괄호(})를 만나면 사라짐 -> 메서드 실행될 뿐만 아니라, if문 반복문 try문 모두 스택프레임이 생기게 됨
참고 링크