JVM과 Garbage Collector
JVM의 구조
클래스 로더
- 런타임에
클래스 파일
에서 바이트코드를 읽어 메모리에 저장합니다. - 로딩 : 클래스를 읽어오는 과정
- 링크 : 참조 포인터를 연결하는 과정
- 초기화 : static 자원들을 초기화하고 변수에 할당합니다.
- 런타임에
런타임 데이터 영역
Method Area
,Heap
,Stack
,PC Register
,Native Method Stack
Method Area
: 모든 스레드가 공유하는 영역으로, 클래스들의 정보 및 바이트 코드들을 저장합니다.Heap
: 런타임에 동적으로 할당되는 영역으로, instance들이 주로 저장됩니다.Thread
: 각 스레드는 아래 3개의 영역을 각자 가지게 됩니다.Stack
: 스택프레임이 저장되는 공간으로, 지역변수, 메소드 매개변수, 메소드 정보 등이 저장됩니다.PC Register
: 현재 수행중인 JVM의 명령어 주소를 저장하는 공간입니다.
스레드는 여기 저장된 데이터를 보고 어떤 부분을 어떤 명령어로 수행할지 이 영역을 보고 결정합니다.
다음 명령의 주소를 저장하는 CPU의 PC Register와는 다르게 동작합니다.Native Method Stack
: Java가 아닌 다른 언어로 작성된 코드를 실행시키기 위한 공간
실행 엔진
- Interpreter : 바이트코드를 기계어로 번역해주는 역할입니다.(사전에 작업됨)
- JIT Compiler : 실행시간에 기계어로 번역합니다.(컴파일 최적화)
- Garbage Collector : 메모리에서 더 이상 사용하지 않는 데이터를 정리합니다.
- Java Native Interface(JNI) : Java가 아닌 소스를 실행할 수 있는 기능을 제공하는 프레임워크 입니다.
- Native Method Library : 다른 언어로 작성된 라이브러리들이며, JNI를 통해 불러 사용합니다.
Garbage Collector
Garbage Collection(GC)
은 적은 횟수로, 효율적이게 메모리를 정리할 수 있는 알고리즘들이 적용되어있습니다.
그 이유는 Garbage Collection
이 수행될 때 발생하는 Stop-the-world
입니다.Stop-the-world
란, GC를 수행하기 위해 JVM이 애플리케이션 실행을 멈추는 것을 의미합니다.
그래서 Stop-the-world
가 자주 발생하면, 프로그램 성능을 심각하게 떨어뜨릴 수 있습니다.
아래에서 Garbage Collection
이 어떻게 동작하는지 알아보겠습니다.
보통 GC는 Mark
and Sweep
이라는 두 단계로 수행됩니다.
Mark
: 현재 메모리에 있는 데이터 중 접근할 수 없는 객체를 선별하는 작업입니다.Sweep
: 접근할 수 없는 객체를 Heap에서 제거하는 작업입니다.(옵션)Compact
: 메모리 단편화를 방지하기 위해, 데이터를 Heap의 시작주소부터 차례대로 쌓는 작업입니다.
GC알고리즘마다 이 작업이 포함될 수도, 안될 수도 있습니다.GC의 구조
Young Generation(YG)
: 새로 생성된 객체들이 할당되는 공간(Minor GC 발생)Eden
: 새로운 객체들이 할당되는 영역Survivor
: 두 개의 영역이 존재하며, 하나의 영역은 반드시 비워져 있어야 한다는 원칙이 있음Old Generation(OG)
: YG에서 오래 살아남은 객체들이 저장되는 공간(Major GC 발생)
CG가 실행되는 순서
- Minor GC
- Eden에 새로운 객체들이 할당됩니다.
- Eden이 가득 차면 Minor GC가 발생하여 접근할 수 없는 객체는 메모리에서 해제됩니다.
- 살아남은 객체들은 Survivor 영역으로 이동하고, age 값이 증가합니다.
- 1~3번을 반복하며 age값이 정해진 기준 이상이 되면, 해당 객체는 OG 영역으로 이동됩니다.
- Major GC
- Survivor에서 넘어온 오래된 객체들이 OG 영역에 쌓입니다.
- OG 영역이 가득차게 되면 Major GC가 발생하여, 접근할 수 없는 객체를 제거합니다.
- Minor GC
Minor GC와 Major GC로 나눠서 제거하는 이유
OG 영역이 YG 영역보다 더 큰 영역을 할당받습니다.
GC는 영역이 가득차면 수행되는데요.
상대적으로 적은 공간을 가지고 있으며, 새로 생성된 객체가 할당되는 YG가 더 자주 가득차게 되고
결과적으로 Minor GC가 Major GC보다 훨씬 더 많이 수행됩니다.
설계자들이 이렇게 GC를 설계한 이유는 다음과 같습니다.- 대부분의 객체는 금방 접근할 수 없는 객체가 된다.
- 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
위의 두 가지 이론을 전제로, YG에서 더 많은 접근할 수 없는 객체가 생길것이라 생각하였기 때문입니다.