JVM이란?
JVM은 JAVA Virtual Machine(자바 가상 머신)의 약자로, 자바 바이트 코드를 실행할 수 있는 주체이다. 자바 바이트 코드는 운영체제(OS)에 독립적이며 모든 JVM은 규격에 정의된 대로 자바 바이트 코드를 실행한다. 또한, JVM은 자바 애플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행한다.
JVM의 동작 방식
자바 프로그램 실행시 동작 방식은 아래의 사진을 참고한다.
1) JVM이 OS로 부터 메모리를 할당받는다.
2) 자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트 코드(.class)로 컴파일 한다
3) Class Loader는 동적 로딩을 통해 클래스들을 로딩 및 링크 하여 Runtime Data Area(실질적인 메모리를 할당 받아 관리하는 영역)에 올린다.
4) Runtime Data Area에 로딩 된 바이트 코드는 Execution Engine을 통해 해석된다.
5) Execution Engine에 의해 Garbage Collector의 작동과 Thread 동기화가 이뤄진다.
JVM의 메모리 구조
JVM은 아래와 같이 구성되어 있다.
- 클래스 로더(Class Loader)
- 실행 엔진(Execution Engine)
- 인터프리터(Interpreter)
- JIT 컴파일러(Just-in-Time)
- 가비지 콜렉터(Garbage collector)
- 런타임 데이터 영역(Runtime Data Area)
- 메소드 영역
- 힙 영역
- PC Register
- 스택 영역
- 네이티브 메소드
- JNI - 네이티브 메소드 인터페이스(Native Method Interface)
- 네이티브 메소드 라이브러리(Native Method Library)
클래스 로더(Class Loader)
클래스 로더는 JVM 내로 클래스 파일(*.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다. 즉, 로드된 바이트 코드(.class)들을 엮어 JVM의 메모리 영역인 Runtime Data Areas에 배치한다(Loading). 클래스 파일의 로딩 순서는 Loading -> Linking -> Initialization의 3단계로 구성된다.
실행 엔진(Excution Engine)
실행 엔진은 클래스 로더를 통해 런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다. 이 과정에서 인터프리터(Interpreter)와 JIT(Just-In-Time) 컴파일러 방식을 혼합하여 바이트 코드를 실행한다.
- Interpreter : 명령어를 하나씩 실행하는 대화형식 컴파일. (파이썬)
- JIT : Interpreter의 단점을 보완하기 위해 도입된 방식. 적절한 시간에 전체 바이트 코드를 네이티브 코드로 변경하여 실행한다. 전체적인 실행 속도가 인터프리팅 방식보다 빠르다.
가비지 컬렉터(Garbage Collector, GC)
JVM은 가비지 컬렉터를 이용하여 Heap 메모리 영역에서 더는 사용하지 않는 메모리를 자동으로 회수해 준다. GC가 수행되는 동안에는 GC를 수행하는 쓰레드가 아닌 다른 모든 쓰레드가 일시 정지된다.
런타임 데이터 영역(Runtime Data Area)
JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.
런타임 데이터 영역은 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나누어져 있다.
메소드 영역(Method Area)
클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 필드 정보와 메소드의 이름, 리턴 타입, 파라미터, 접근 제어자 정보 같은 method 정보들, Constant Pool, Static 변수, final class변수 등이 생성되는 영역
힙 영역(Heap Area)
new 연산로 생성되는 클래스와 변수, 배열 타입 등 Reference Type이 저장되는 영역. 메소드 영역에 로드된 클래스만 생성이 가능하며 GC가 참조되지 않는 메모리를 확인하고 제거함
스택 영역(Stack Area)
정적 메모리 할당이 이루어지는 장소로 지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값, 메서드 호출 등 임시적인 데이터들이 생성되는 영역. 선입후출 구조다.
Person person = new Person();
/*
person은 Stack영역
new Person()은 Heap영역에 할당
*/
PC 레지스터(PC Register)
스레드가 생성될 때마다 생성되는 영역. 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역.
Native Method Stack
자바 외의 언어로 작성된 Native 코드를 위한 메모리 영역. 보통 C/C++ 등의 코드를 수행하기 위한 Stack이다.
위의 내용을 표로 정리하면 아래와 같다.
영역 | 용도 | 사용기간 | 스레드 공유 |
Method(Static) | JVM에서 읽어들인 클래스와 인터페이스에 대한 런타임 상수 풀, 메서드와 필드, Static 변수, 메서드 바이트 코드 등을 보관 | JVM 시작시 생성. 프로그램 종료 시까지. 명시적으로 null 선언시 GC 대상. | 모든 스레드에서 공유 |
Runtime Constant Pool | Method Area 영역에 포함되지만 독자적 중요성을 띔. 클래스 파일 constant_pool 테이블에 해당하는 영역. 클래스와 인터페이스 상수, 메서드와 필드에 대한 모든 레퍼런스 저장. JVM은 런타임 상수 풀을 통해 메서드나 필드의 실제 메모리 상 주소를 찾아 참조 |
||
Heap Area | 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 메모리 영역. New연산자를 통해 생성한 객체 또는 인스턴스와 배열을 저장 | 객체를 더 이상 쓰지 않거나 명시적으로 null 선언시 GC대상. | |
Stack Area | 선입후출(FILO) 구조, 메서드 호출 시 생성되는 스레드 수행정보를 기록하는 Frame 저장, 메서드 정보, 지역변수, 매개변수, 연산 중 발생하는 임시 데이터 저장 | {}나 메서드가 끝날 때 | 각 스레드별로 생성 |
PC Register | 현재 실행중인 JVM의 주소를 갖고 있음. CPU 명렁어(Instruction) 수행. 수행 중 필요한 정보를 CPU내 레지스터에 저장 |
||
Native Method Stack Area | 자바 외 언어로 작성된 네이티브 코드를 위한 메모리(C/C++ 등). native 메서드의 매개변수, 지역변수 등을 바이트 코드로 저장 | native interface 호출 시 생성 native interface 종료 시 생성 |
https://inpa.tistory.com/entry/
https://velog.io/@dyunge_100/JAVA-JVM의-메모리-구조-및-동작-원리
'Backend > JAVA' 카테고리의 다른 글
[JAVA] iterator와 iterable의 차이는 무엇일까? (0) | 2024.01.24 |
---|---|
[JAVA] Stream API란? Java Stream API의 특징은? (0) | 2024.01.19 |
[Java] #19.3 자바 입출력 - char 단위 입출력 (0) | 2023.08.15 |
[Java] #19-2 자바 입출력 - byte 단위 입출력 (0) | 2023.08.14 |
[Java] #19.1 자바 입출력 - 파일 관리와 문자셋 (0) | 2023.08.13 |