나름 정리한다고 해봤는데 너무 어렵다.. 계속 보완을 해야한다.
가비지 컬렉터는 두 가지 전제 조건(Weak Generation Hypothesis)을 기반으로 만들어졌다
- 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
- 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
JVM의 종류가 많은 만큼 GC또한 다양한 벤더가 배포했다.
그래도 모든 GC는 다음 원칙을 지켜야한다.
- GC알고리즘은 반드시 모든 Grabage를 수집해야 한다.
- 아직 살아있는 객체는 절대 수집해서는 안된다.
아직 살아있는 객체를 수집하면 Segmentation Fault가 일어나거나 프로그램 데이터가 조용하게 망가진다.
Segmentation Fault
Segfault로 줄여서 말하기도 한다. 프로그램이 허용되지 않은 메모리 영역에 접근을 시도하거나 허용되지 않은 방법으로 메모리 영역에 접근을 시도할 경우 발생한다.(ex : read only 영역에 write를 시도하거나 os에서 사용하는 영역에 다른 내용을 덮어쓰려 하는 경우)
STW(Stop The World)
GC을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다. stop-the-world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생한다. 대개의 경우 GC 튜닝이란 이 stop-the-world 시간을 줄이는 것이다.
Garbage Collection
Mark and Sweep 알고리즘을 기초로 동작한다.
핫스팟 VM에서는 다음 조건으로 Garbage Collection이 동작한다.
- 객체마다 세대 카운트(객체가 지금까지 무사 통과한 garbage collection count)를 센다.
- 큰 객체를 제외한 나머지 객체는 eden영역에 생성한다. 여기서 살아남은 객체는 다른 곳(survivor area)으로 옮긴다.
- 장수했다고 할 정도로 충분히 오래 살아남은 객체들은 별도의 메모리 영역(old area)에 옮긴다.
핫스팟 VM에서는 크게 2가지로 물리적 공간을 나누었다.
Young 영역과 Old 영역이다.
Young 영역
새롭게 생성한 객체의 대부분이 여기에 위치한다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라진다. 이 영역에서 객체가 사라질때 Minor GC가 발생한다고 말한다.
Young 영역은 다시 3개의 영역으로 구분된다.
eden 영역1개와 survivor 영역2개이다.
새로 생성한 대부분의 객체는 Eden 영역에 위치한다.
Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.
Eden 영역에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역으로 객체가 계속 쌓인다.
하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다. 그리고 가득 찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.
이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.
이 절차를 확인해 보면 알겠지만 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 한다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 여러분의 시스템은 정상적인 상황이 아니라고 생각하면 된다.
Old 영역
접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사된다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.
Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행한다. GC 방식에 따라서 처리 절차가 달라지므로, 어떤 GC 방식이 있는지 살펴보면 이해가 쉬울 것이다. GC 방식은 JDK 7을 기준으로 5가지 방식이 있다. (하지만 여기 글에서는 대표적인 2개만 작성한다.)
Serial GC
Young 영역에서의 GC는 앞 절에서 설명한 방식을 사용한다. Old 영역의 GC는 mark-sweep-compact이라는 알고리즘을 사용한다. 이 알고리즘의 첫 단계는 Old 영역에 살아 있는 객체를 식별(Mark)하는 것이다. 그 다음에는 힙(heap)의 앞 부분부터 확인하여 살아 있는 것만 남긴다(Sweep). 마지막 단계에서는 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워서 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다(Compaction).
Parallel GC
가장 단순한 Young 세대 전용 병렬 수집기 Parallel GC는 Serial GC와 기본적인 알고리즘은 같지다. 그러나 Serial GC는 GC를 처리하는 스레드가 하나인 것에 비해, Parallel GC는 GC를 처리하는 쓰레드가 여러 개이다. 그렇기 때문에 Serial GC보다 빠른게 객체를 처리할 수 있다. Parallel GC는 메모리가 충분하고 코어의 개수가 많을 때 유리하다. Parallel GC는 Throughput GC라고도 부른다.
reference
[2] : https://d2.naver.com/helloworld/1329
[3] : 자바 최적화 - 가장 빠른 성능을 구현하는 검증된 10가지 기법
[5] : https://www.oracle.com/java/technologies/javase/vmoptions-jsp.html
'JAVA' 카테고리의 다른 글
자바 인터뷰 질문 - 기본기 (2) (0) | 2021.07.03 |
---|---|
자바 인터뷰 질문 - 기본기 (1) (0) | 2021.06.17 |
[JAVA] new와 ""의 차이 / string constant pool (0) | 2021.06.06 |
접근 제어자 (0) | 2021.05.05 |
저는 Eclipse로 개발합니다(1) - debugging (0) | 2021.03.25 |