JVM(자바 가상 머신, Java Virtual Machine)은 자바 프로그램의 실행 환경을 제공하는 소프트웨어다. 자바 코드를 바이트 코드(컴퓨터가 이해할 수 있는 기계어)로 변환하고, 이를 통해 어떤 운영 체제에서도 자바 코드를 실행할 수 있게 해준다.
JVM의 작동원리는 (1) 자바파일(.java) 생성 후 자바 컴파일러(javac)에 의해 바이트 코드(.class)로 변환하고, (2) JVM을 통해서 바이트 코드를 컴퓨터가 이해할 수 있는 바이너리 코드로 변환하여 실행한다.
JVM의 메모리구조
JVM은 3가지 모듈을 가지고 있다.
- Garbage Collector (GC)
더 이상 사용하지 않는 객체를 감지하고 메모리에서 제거하여 메모리를 회수하는 역할을 한다.
- Execution Engine
바이트 코드를 해석하고 실행하는 역할을 한다. - Class Loader
.class 파일을 가지고 와 메모리에 적재한다.
이 세 가지 모듈을 통해 JVM은 자바 프로그램을 실행하며, 다음과 같은 데이터 영역(Runtime Data Area)을 생성한다.
데이터 영역 (Runtime Data Area)
Method area (class area)
클래스에 대한 메타데이터, 클래스 변수, 메소드 정보를 저장한다. JVM이 클래스를 로드할 때 이 영역에 적재된다. 전원이 꺼지거나 시스템이 종료되기 전까지 메모리가 유지되며, public, static, void, main과 같은 메서드와 클래스의 구조 정보가 이 영역에 저장된다.
Heap area
모든 객체와 해당 인스턴스 변수가 저장되는 영역이다. 예를 들어서 Food food = new Food();와 같은 코드를 실행하면 Food 클래스가 로드되고, food 인스턴스가 Heap area에 적재된다. 사용하고자 하는 스택의 가장 아래 부분부터 메모리 주소를 링크하여 적재한다. 객체에 대한 메인 주소가 더 이상 사용되지 않으면 garbage collector(GC)에 의해 메모리가 회수 된다.
Stack area
메서드 작업에 필요한 메모리가 제공되는 공간으로, 메서드가 호출되면 호출 스택에 프레임이 쌓이고(메모리 할당) 종료되면 해당 프레임(메모리 반환)이 제거된다. 맨 위의 메서드 하나만 실행되며 나머지 메서드는 대기한다. 메서드가 끝나면 메모리는 자동으로 반환된다. 스택은 휘발성 메모리이기 때문에 프로그램이 종료되면 스택에 저장된 모든 데이터가 사라진다.
Program Counter Register
현재 실행 중인 JVM 명령어의 주소를 저장한다.
Native Method Stack
Java가 아닌 네이티브 메서드를 호출할 때 사용된다.
예를 들어, Food food = new Food();를 통해 인스턴스를 생성하면, JVM은 우선 스택에서 food 인스턴스에 대한 메모리를 할당한다. 이후, Food 클래스의 필드 값 및 타입에 대한 정의는 Heap 영역에서 가져와 사용된다. Heap에서 사용하는 메모리는 Method Area에서 정의된 클래스 메타데이터를 기반으로 한다.
package com.example1;
// Method Area : Food 클래스와 Test클래스의 메타데이터, 메서드 정보가 저장
class Food {
String name;
// 생성자
public Food(String name) {
this.name = name;
}
void eat() {
System.out.println(name + "을 먹습니다.");
}
}
class Test {
// Stack Area : main메서드 호출 시 프레임이 스택에 추가
public static void main(String[] args) {
System.out.println("main(String[] args)이 시작되었음.");
//Heap Area : Food 인스턴스 생성, Heap Area에 저장됨
Food food = new Food("사과");
food.eat();
firstMethod();
System.out.println("main(String[] args)이 끝났음.");
}
static void firstMethod() {
System.out.println("firstMethod()이 시작되었음.");
secondMethod();
System.out.println("firstMethod()가 끝났음.");
}
static void secondMethod() {
System.out.println("secondMethod()이 시작되었음.");
System.out.println("secondMethod()이 끝났음.");
}
}
'Backend > Java' 카테고리의 다른 글
Java 기초 문법 : 컬렉션(collection) - Set (2) (0) | 2024.10.10 |
---|---|
Java 기초 문법 : 컬렉션(collection) - List (1) (0) | 2024.10.10 |
Java 기초 문법 : 제네릭(generic) (0) | 2024.10.08 |
JAVA : 레코드(Record)에 대해서 (0) | 2024.10.07 |
Java 기초 문법 : 인터페이스(interface) (1) | 2024.06.19 |
Java 기초 문법 : 다형성(polymorphism) (0) | 2024.06.13 |
Java 기초 문법 : 제어자(modifier) (1) | 2024.06.13 |
Java 기초 문법 : 패키지, import문 (1) | 2024.06.13 |