JVM(Java Virtual Machine)이 OS로 부터 메모리를 할당 받아 .class파일(byte code)를 실행시킬때에
메모리에 대해 알아보겠습니다. ①②③④⑤⑥⑦⑧⑨⑩⑪⑫
1. JVM 메모리 구조
JVM은 다음과 같은 메모리 구조를 가지고 있습니다.
오늘은 .class파일을 실행 시켰을떄 간단한 예제와 함께 JVM의 메모리에 메서드가 올라가고 제거되는 과정을 살펴보겠습니다.
따라서 위 그림의 빨간색 영역에 대해서만 다루겠습니다.
2. JVM Runtime Data Area(Memory Area) 구조
JVM은 Runtime에 Data를 올려놓는 영역인 Runtime Data Area를 가지고 있습니다. 이 영역은 크게 5가지로 나뉘지만,
위 그림 이외의 두 영역은 Low Level 의 Operation을 다루기 위한 공간이므로 여기서는 다루지 않겠습니다.
Method Area
Method Area는 Static Area라고도 불리며 보통 정적 메모리라 부르는 영역입니다.
이 글에서는 메서드의 호출과 JVM의 메모리를 다룰 것이기 때문에 class, interface등은 다루지 않겠습니다.
Java Compiler에 의해 컴파일된 .class파일(byte code)이 올라오며,
JVM을 실행하기 위한 필수적인 main() 메서드와 main 메서드의 실행중 사용되는 메서드를이 이곳에 올라옵니다.
Stack Area
그림을 위해 임의적으로 나타낸 스택영역은 Thread당 1개로 생성되며 각 Stack은 영역을 공유하지 않고 독립적입니다.
JVM 명세서에 따르면 thread와 함께 생성되며, 호출된 메서드의 로컬 변수(local variables), 매개 변수(parameters) 가 올라옵니다.
이때 로컬변수와 매개변수가 Primitive Type(char, byte, short, int , long, float, double, boolean)이 아니라면 데이터 자체는 heap영역에 올라가며 이를 참조하는 변수는 Stack 영역에 올라갑니다.
Heap Area
힙영역은 JVM에 한개만 존재하며 힙영역은 모든 Thread가 공유합니다.
JVM의 실행과 동시에 생성되며 객체(인스턴스)가 올라옵니다.
힙영역에 생성된 객체는 스택영역의 다른 변수에 의해 참조되며, 스택영역의 변수는 이 객체의 메모리 주소값을 가리키고 있습니다.
3. 예제를 통한 JVM의 Memory 관리 과정
3.1
public class Exam01 {
static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.printf("swap(): a=%d, b=%d\n", a, b);
}
public static void main(String[] args) {
int a = 100;
int b = 200;
swap(a, b);
System.out.printf("main(): a=%d, b=%d\n", a, b);
}
}
- JVM이 Exam01 클래스 정보를 Method Area 영역에 로드합니다.(클래스 정보인 byte code와 main(), swap() 메서드가 올라감)
- main() 메서드를 호출합니다.
- main() 메서드가 실행되면 Stack영역에 main() 메서드의 매개변수 args 로컬변수 a, b가 생성됩니다.
- args 매개변수가 참조하는 String[] 객체는 힙 영역에 올라갑니다.
- swap() 메서드가 호출됩니다.
- swap() 메서드가 실행되면 Stack영역에 swap() 메서드의 매개변수 a, b 와 로컬변수 temp가 생성됩니다.
- swap() 메서드로 인해 Stack영역의 매개변수 a, b의 값이 바뀌며 printf문이 실행됩니다.
- swap() 메서드가 종료되며 Stack 영역에서 swap() 메서드가 사용한 메모리를 제거합니다.
- main() 메서드의 printf문이 실행됩니다.
- main() 메서드가 종료되며 Stack 영역에서 main() 메서드가 사용한 메모리를 제거합니다.
- JVM이 실행을 종료하며 OS가 JVM에게 할당했던 메모리를 회수합니다.
이때, JVM은 Stack영역을 각 메서드 별로 사용할 수 있는 메모리의 공간을 frame이라는 가상의 영역으로 나누어 관리합니다.
따라서, swap() 7번의 과정은 9번에서 확인할수 있는 main()메서드의 지역변수 a, b의 값에 영향을 주지 않습니다.
3.2
public class Exam02 {
static int m1(int value) {
int r1 = m2(value);
int r2 = m3(value);
return r1 + r2;
}
static int m2(int value) {
return value + 100;
}
static int m3(int value) {
return value + 200;
}
public static void main(String[] args) {
int r = m1(5);
System.out.println(r);
}
}
- JVM이 Exam02 클래스 정보를 Method Area 영역에 로드합니다.
- main() 메서드를 호출합니다.
- main() 메서드가 실행되면 Stack영역에 main() 메서드의 매개변수 args 로컬변수 r이 생성됩니다.
- 로컬 변수 r은 m1(5)의 값을 받기위한 준비상태입니다.
- args 매개변수가 참조하는 String[] 객체는 힙 영역에 올라갑니다.
- m1() 메서드가 호출됩니다.
- m1() 메서드가 실행되면 Stack영역에 m1() 메서드의 매개변수 value 와 로컬변수 r1, r2가 생성됩니다.
- r1, r2 역시 m2(5), m3(5)의 값을 받기위한 준비상태입니다.
- m2() 메서드로 인해 Stack영역의 매개변수 value의 값 5가 생성되며 m1() 메서드의 stack frame의 r1에 값을 반환과 동시에 m2()메서드의 stack memory가 제거됩니다.
- m3() 메서드로 인해 Stack영역의 매개변수 value의 값 5가 생성되며 m1() 메서드의 stack frame의 r2에 값을 반환과 동시에 m3() 메서드의 stack memory가 제거됩니다.
- m1() 메서드는 r1 + r2를 반환하며 stack영역의 메모리에서 제거됩니다.
- Stack 영역의 변수 r에 r1 + r2의 값을 저장합니다.
- main() 메서드의 print문이 실행됩니다.
- main() 메서드가 종료되며 Stack 영역에서 main() 메서드가 사용한 메모리를 제거합니다.
- JVM이 실행을 종료하며 OS가 JVM에게 할당했던 메모리를 회수합니다.
'Java > 기초' 카테고리의 다른 글
[Java] 간단한 ConnectionPool 구현 해보기(JDBC Driver, Connection) (0) | 2024.02.21 |
---|---|
[Java] 비트 연산자(Bitwise Operator) (1) | 2023.11.27 |
[Java] Enum(열거형) (1) | 2023.11.02 |
[Java] Iterable 인터페이스와 Iterator (0) | 2023.11.01 |
[Java] Network Programming(네트워크 프로그래밍) (0) | 2023.11.01 |