본문 바로가기
질문을 해결하는 과정

[JVM] 3분만에 훑어보는 JVM의 가상 메모리 구조

by 무자비한 낭만주먹 2024. 1. 15.

[그림1]. 오늘도 감사한 공부 시작 ~

목차
0. 개요
1. JVM 청사진
2. STACK
3. PC 
4. Native Method Stack 
5. Method
6. Heap
7. 결론

 

 

0. 개요
a. JVM 가상 메모리 구조, 설명들이 다 너무 어려워 ..
(1) 왜 어려울까?
주제가 명확하지 않다.


보면 STACK은 말할것도 없고 METHOD, HEAP 영역 넘어가면 GC가 어쩌니 MetaSpace가 어쩌니 복잡한 주제로 넘어가는 글밖에 없어서 그런 거 같다. 그래서 오늘은 그냥 'JVM 가상 메모리 구조' 에 대해서만 딱 정리하려 한다.

3분만에 끝내보자.



 

 

1. JVM 청사진
a. JVM은 프로세스다.
(1) JVM은 프로세스다.

 

[그림2]. JVM은 그냥 프로세스다.
JVM은 지가 진짜 운영체제라도 된 냥 행동하지만 그냥 결국 프로세스다.


JVM은 프로세스다. 이 말은 OS로 부터 메모리 영역을 할당받고 CPU를 할당 받는다는 의미인데, 이 놈은 지가 마치 진짜 운영체제라도 된 냥 내부적으로 자기만의 가상 메모리를 구분하고 관리한다.





b. JVM의 가상 메모리
(1) 5가지 가상 메모리 분류

 

[그림3]. JVM의 가상 메모리 분류
JVM은 5가지 영역으로 가상 메모리를 분류한다.


이 영역들은 '쓰레드 별로 생성되는 영역'과 '모든 쓰레드에 공유될 수 있는' 영역으로 나뉜다.

 

(2) 쓰레드별로 생성되는 영역
[그림4]. 쓰레드별로 생성되는 영역
쓰레드의 흐름을 표현하기 위한 3가지 영역이 있다.


JVM은 프로세스기에 '스레드'를 통해 작업 흐름을 분기할 수 있는데, 이 내용은 맨 뒤에 부록에 작성해둘테니 이해가 어려울 경우엔 그냥 '아~ 작업 흐름을 여러개 만들 수 있고 그 흐름별로 메서드 호출 정보 같은 걸 쌓는데 필요한 녀석들이구나' 정도만 이해하면 될 거 같다.

 

(3) 모든 쓰레드에 공유될 수 있는 영역
[그림5]. 모든 쓰레드에 공유될 수 있는 영역
클래스에 대한 메타 데이터와 동적 정보들


이 영역들은 클래스에 대한 메타정보나 동적인 정보들을 저장하는데 사용되는 영역들이다. 이런 정보들은 쓰레드별로 지역적으로 사용되기보단 공유되야 하는 성질이 강해 이론적으론 모든 쓰레드에서 접근 가능한 영역들이다.

 

 

 

2. STACK
a. 이 놈이 하는 일
(1) 스레드의 흐름 표현
[그림6]. STACK AREA
STACK 영역은 메서드의 흐름을 표현한다.


STACK 영역은 'STACK FRAME' 이라는 단위 정보가 적재되는데 얘는 사실 별 거 아니고 '메서드 호출 정보'정도 되는 녀석이다. 그러니까 메서드 호출 정보들을 LIFO(Last In First Out)구조로 적재해야 우리가 지금 사용하고 있는 메서드 처럼 '마지막에 호출된 녀석이 먼저 완료' 되는 상태를 만들 수 있기에 STACK 구조를 쓰는 것이다.



 

b. 간단한 예제
(1) 스레드의 스택 프레임 확인
[그림7]. 스택 프레임 쌓아보기
그냥 메서드 호출 관련된 정보를 담아두는 녀석이다.

 

c. 어디서 많이 봤는디 ..
(1) 아하 !

 

[그림8]. 우리가 자주 보는 스택 프레임
결국 문제가 난 곳은 맨 위에 있다.


사실 LIFO 구조이기 때문에 해당 스레드 작업이 끊긴 부분은 제일 위에서 확인할 수 있다. 에러 확인할 때 위에서 부터 봐야 하는게 이런 원리 때문이다.

 

 

3. PC 
a. 이 놈이 하는 일
(1) 그냥 '최근 작업 위치 저장하기'

 

[그림9]. JVM 가상 메모리 영역 중 pc
CPU 점유를 뺏겨도, 다시 시작하기 위해


사실 해당 스레드가 끝날 때 까지 항상 'CPU 점유'를 보장받을 순 없다. 그래서 중간에 작업 하다 말고 멈춰야 하는데 이 때 어디까지 작업했는지 기록해주는 역할을 하는게 pc register이다.

 

 

4. Native Method Stack 
a. 이 놈이 하는 일
(1) 자바에서 C 코드 사용하기

 

[그림10]. native method stack과 JNI
JNI, Java Native Interface를 이용해 Native Method Library의 네이티브 코드를 사용토록 하는 것

 



b. 우리가 쓰고 있던 c 코드
(1) Thread.currentThread()
[그림11]. 우리가 쓰고있던 native method
우리가 자바 코드인 줄 알고 쓰고 있던 native method들

 
흔히 쓰는 메서드들도 들어가보면 'native'라는 키워드가 붙어있는 걸 볼 수 있다. 저렇게 되면 JNI를 이용해 Native Method Library를 뒤져서 Native method Stack에 적재하게 된다.

 

 

 

5. Method
a. Method Area 청사진
(1) 이 부분 .. 중요하고, 복잡하다.

 

[그림12]. method 구현의 변천사
java 8 버전 이전에는 method 영역은 heap 영역 아래 있었다.


이 부분은 복잡한 내용이어서 깊게 설명하진 않지만, 되게 중요한 부분이어서 차후에 따로 다루겠다.
어쨌든 얘기하고 싶은 부분은 method 영역에 대한 구현 주체가 바뀌었다는 점이다. Java 8 이전에는 permanent generation이라고 하는 Java Heap 하위 영역에 구현됐었지만 java 8부터는 Native Memory라는 Java heap 메모리와 별도로 존재하는 시스템 heap 영역에 Metaspace구현되게 된다.

물론 관리는 여전히 JVM의 책임이지만 이 상호작용에 OS와 결합도가 더 높아졌다는데에 의미가 있다. 



b. 그래서 이게 뭐냐고
(1) 클래스의 메타 정보들 저장하는 거 ..

 

[그림13]. java 8 이전의 method Area에서 다루는 데이터 중 일부
그냥 클래스 메타 정보 저장하는 놈


사실 저 static 변수 같은 녀석도 java 8부터는 heap 쪽으로 넘어가서 표현하기가 여간 껄끄럽다. 그래서 위 기준은 java 7 기준이라고 가정하고 설명한 것이다. 디테일한 내용은 그때 그때 검색해보면 될 거 같고 중요한 내용은 저런 '클래스 표현을 위한 메타 데이터들을 저장해두는 곳' 정도로 이해하면 될 거 같다.

 

 

 

6. Heap
a. 이 놈이 하는 일
(1) 동적 정보 관리하는 놈

 

[그림14]. JVM의 Heap Area
new 하던지 배열을 만들던지


HEAP은 GC 관련해서 설명하면 내용이 너무 복잡해진다. (Method도 마찬가지지만) 그래서 대략적인 내용만 정리하자면, 그냥 '동적 정보 관리하는데 필요한 가상 메모리 영역'이다.

'Minor, Major, Full GC 등의 '객체 청소'를 위해 내부적으로 Young, OLD 영역 나눠놓는 영역이다' 정도 까지만 이해하면 될 거 같다.

 

 

 

7. 결론
a. 메모리를 이해하는 건 중요하다.
(1) 왜?
이건 지금 더 고민중 ..


일단 한숨 자고 생각 예정

 

 

 

 

오늘 하루도 공부할 수 있어 크게 감사합니다

2024-01-15 개발자 최찬혁