JVM

JVM 메모리 구조

samryong 2024. 3. 13. 23:03

지난 글에서 JVM의 ClassLoader에 대해서 소개했습니다. ClassLoader가 바이트 코드를 읽어와서 데이터를 메모리에 적재하는 흐름으로 이어져서 오늘은 JVM 동작 흐름상의 JVM의 메모리 구조에 대해서 알아보도록 하겠습니다. JVM 메모리 자체만으로도 공부하면 공부량이 너무 많고 이 글에서 그걸 다 적다 보면 본래 의도(JVM의 동작과정)와 다르게 메모리의 구조 자체에 포커스가 될거 같아서 간단하게 흐름에 필요한 만큼만 설명을 드리도록 하겠습니다.

 

 

 

JVM에서 메모리의 구성은 PC Register, Stack, Native Method Stack, Heap, Method Area 크게 5가지로 구분 할 수 있습니다.

위 그림을 보면 PC Register, Stack, Native Method Stack은 Thread 마다 할당되는 메모리이고 Heap과 Method Area는 공통 메모리로 사용됩니다. 

 

각 구성 별 역할 및 특징

 

- Method Area 

 

 static 변수, 클래스의 필드, 클래스의 메서드 및 생성자를 저장합니다(이러한 것들을 Runtime Constant Pool 영역에 저장됩니다.). 모든 쓰레드들의 공유 자원으로 JVM이 시작될 때 생성되고 JVM이 종료될때 사라집니다. 몇몇 블로그들 글을 읽다가 Method Area 영역의 데이터들은 GC(Gabage Collerctor)의 관리 대상이 아니라고 설명하는데 이부분은 Oracle 공식문서에서 설명하기를 JVM Vendor에 따라 다르다고 설명하고 있습니다. 이부분은 독자분들이 사용하는 JVM Vendor에 따라 공식문서를 확인해보시는게 좋을 거 같습니다. 

 

- Heap Memory

 

여기에 저장되는 데이터로는 Instance 객체, Instance 변수(클래스의 전역 변수), 배열의 데이터가 저장되고 GC(Gabage Collector)에 의해 더이상 사용되지 않는 데이터는 삭제가 되는 메모리 영역입니다. GC와 밀접하게 관련된 부분이라 이부분에서는 GC관련 글을 적을때 더 자세하게 적도록 하겠습니다. 

 

(1) Eden : 최초의 Instance 객체 및 변수들이 사용 될 때 이 공간에 저장이 됩니다.

(2) Servivor1 : GC에 의해 불필요한 데이터들이 정리 될 때 살아 남은 데이터가 Eden 에서 Servivor1으로 이동하게 됩니다.

(3) Servivor2 : GC가 작동할 때 Servivor1에서 정리 되지 않은 데이터가 Servivor2로 이동하게 됩니다.

(4) Old : Servivor2에서도 생존 했을 때 Old로 이동하게 된다 

(5) Permanent : 이곳이 Method Area입니다. JVM7버전까지는 Permanent로 Heap 메모리에 존재했습니다.

 

JVM8 이후의 Heap Memory의 변화

 

 

PerManent의 제거이다 기존에는 JVM Heap 메모리에서 Class의 Meta Data를 저장하고 관리했는데 JVM8 버전으로 가면서 PerManent가 사라지고 이 역할을 하던 공간이 MetaSpace라는 영역으로 생기고 Native Memory에 새로 생기게 되었다. 그래서 이 둘의 차이를 설명하자면 기존에 Heap Memory에 존재했을 때 제한된 작은 영역을 가지고 있었습니다. 하지만 Native Memory에 둠으로 써 OS 메모리에 Class Meta Data를 올림으로써 JVM에서 이부분에 대한 메모리 설정을 따로 하지 않아도 따로 제한이 없어져서 관리 부분에서 편리성을 갖게 되었습니다.

 

 

- Stack

 어떤 기능이 실행 될 때 쓰레드마다 런타임 스택을 만들고, 그 안에 메소드 호출을 Frame이라는 이름이라는 부르는 블럭을 쌓습니다. Frame에는 지역 변수와 실행에 필요한 메모리 확보를 위한 Operand Stack이 존재하고 Constant Pool 참조값을 가지고 있으며 실행이 끝나면 Frame은 사라집니다.

 

- PC Register

 각 스레드마다 현재 수행 중인 JVM 명령의 주소가 저장되는 영역입니다. 

현재 실행되고 있는 명령어 instruction의 주소를 저장합니다. Multi thread 환경에서 한 thread가 작업하다가 다른 thread로 잠시 CPU 점유를 넘겨주고 다시 돌아왔을 때 이전에 어떤 명령을 수행하고 있었는지를 기억하고 있어야 이전 작업을 다시 이어서 할 수 있도록 도와줍니다.

 

- Native Method Stack 

C / C++로 만들어진 Native 함수를 호출시 실행시키기 위한 Stack입니다.