본문 바로가기

개발/JVM

Garbage Collection

| GC(Garbage Collector)

 

GC는 더 이상 참조되지 않는 객체들을 힙 메모리에서 제거하는 역할을 합니다

 

 

| Week Generational 가설

 

GC는 아래 두가지 가설을 통해 만들어 졌습니다 (Young Generation, Old Generation 개념)

 

 - 대부분의 객체는 금방 접근 불가능한 상태가 된다

 - 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다

 

 

| Mark And Sweep Algorithm

 

자바 GC 알고리즘의 기본은 'Mark And Sweep'입니다

살아있는 객체의 mark bit에 true(1)를 표시(mark)한 후 mark bit가 false(0)인 객체들을 찾아 정리(Sweep)합니다

 

 

| stop-the-world

 

GC에 대해 알기 위해서는 stop-the-world 라는 것에 대해서 알아야 합니다

stop-the-world란 GC를 실행하기 위해서 JVM 어플리케이션이 실행을 멈추는 것을 말하는데

GC를 실행하는 쓰레드를 제외한 모든 쓰레드가 정지되기 때문에

결국 GC 튜닝이란 stop-the-world 시간을 최소화 하는 것이라고 할 수 있습니다


| 힙 영역(Heap Area)

 

JVM 메모리에서 힙 영역은 GC의 주요 대상이 되는 영역입니다 (참고로 메소드, 스택 영역도 GC 대상입니다)

* java8부터 Perm. 영역이 Metaspace로 변경되었습니다

* To,From영역은 S0,S1영역 이라고도 합니다

* Tenured영역은 Old영역 이라고도 합니다

 

Young 영역(Young Generation):

새롭게 생성된 대부분의 객체들이 여기에 위치합니다

대부분의 객체는 금방 접근 불가능한 상태가 되기 때문에 많은 객체가 Young영역에 생성되었다가 사라집니다

이 영역에서 객체를 지우는 것을 Minor GC라고 합니다

 

- 새로 생성된 객체는 Eden영역에 위치한다

- Eden에서 GC가 한번 일어난 후에 살아남은 객체는 Survivor영역 중에 하나로 이동한다

- Eden에서 GC가 발생할 때 마다 Survivor영역(S0/S1)에 살아남은 객체가 쌓이게 된다

- 하나의 Survivor영역이 가득차면 다른 Survivor 영역으로 이동하게 된다. (원래 있던 Survivor 영역은 빈상태가 된다)

- 이 과정을 반복하다 살아남은 객체는 Old 영역으로 간다

 

Old 영역(Old Generation):

접근 불가능한 상태로 되지 않아 Young영역에서 살아남은 객체들이 이 곳으로 복사됩니다

대부분 Young영역보다 크게 할당되며, 크게 할당된만큼 Young역역 보다는 GC가 적게 일어납니다

이 영역에서 객체를 지우는 것을 Major GC(혹은 Full GC)라고 합니다

 

- Old영역에서 Young 영역을 참조하고 있는 경우는 어떻게 하나?

그래서 Old 영역에는 카드테이블이 존재한다고 합니

모든 Old영역을 뒤져본 후에 GC가 일어나는게 아니라 카드테이블 정보만 보고 GC가 일어나게 됩니다

 

Metaspace:

JVM이 사용하는 네이티브 메모리 공간입니다

 

 

-JVM 메모리 내에서 객체의 Lifecycle

 


| GC의 종류 (HotSpot JVM)

 

Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행합니다

GC 방식에 따라서 처리 절차가 달라지므로, 어떤 GC 방식이 있는지 살펴보겠습니다

(자세한 내용은 https://d2.naver.com/helloworld/1329 참고)

 

Serial GC

옵션: -XX:+UseSerialGC

Serial GC는 적은 메모리와 CPU 코어 개수가 적을 때 적합한 방식이며, 단일 Thread가 GC를 수행한다.

 

Parallel GC

옵션: -XX:+UseParallelGC

Parallel GC는 Serial GC와 기본적인 알고리즘은 같다. 그러나 Serial GC는 GC를 처리하는 thread가 하나인 것에 비해, Parallel GC는 GC를 처리하는 thread가 여러 개이다. 따라서 Serial GC보다 빠른게 객체를 처리할 수 있다. Parallel GC는 메모리가 충분하고 코어의 개수가 많을 때 유리하다.

 

Parallel Old GC

옵션: -XX:+UseParallelOldGC

Parallel Old GC는 JDK 5 update 6부터 제공한 GC 방식이다. 앞서 설명한 Parallel GC와 비교하여 Old 영역의 GC 알고리즘만 다르다. 이 방식은 Mark-Summary-Compaction 단계를 거친다. Summary 단계는 앞서 GC를 수행한 영역에 대해서 별도로 살아 있는 객체를 식별한다는 점에서 Mark-Sweep-Compaction 알고리즘의 Sweep 단계와 다르며, 약간 더 복잡한 단계를 거친다.

 

CMS GC

옵션: -XX:+UseConcMarkSweepGC

initial Mark>Concurrent Mark>RemarkConcurrent Mark,Concurrent Sweep의 경우 다른 Thread가 실행중인 상태에서 동시에 진행되기

때문에 stop-the-world 시간이 매우 짧다. 모든 애플리케이션의 응답 속도가 매우 중요할 때 CMS GC를 사용하며, Low Latency GC라고도 부른다.

 

그런데 CMS GC는 stop-the-world 시간이 짧다는 장점에 반해 다음과 같은 단점이 존재한다.

1. 다른 GC 방식보다 메모리와 CPU를 더 많이 사용한다.

2. Compaction(조각모음) 단계가 기본적으로 제공되지 않는다.

 

따라서, CMS GC를 사용할 때에는 신중히 검토한 후에 사용해야 한다. 그리고 조각난 메모리가 많아 Compaction 작업을 실행하면 다른 GC 방식의 stop-the-world 시간보다 stop-the-world 시간이 더 길기 때문에 Compaction 작업이 얼마나 자주, 오랫동안 수행되는지 확인해야 한다.

 

G1 GC

옵션: -XX:+UseG1GC

G1 GC는 바둑판의 각 영역(Region)에 객체를 할당하고 GC를 실행한다. 그러다가, 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 GC를 실행한다. 즉, 지금까지 설명한 Young의 세가지 영역에서 데이터가 Old 영역으로 이동하는 단계가 사라진 GC 방식이라고 이해하면 된다. G1 GC는 장기적으로 말도 많고 탈도 많은 CMS GC를 대체하기 위해서 만들어 졌다. (조각모음이 필요 없음)기존 JVM메모리 구조와는 다르게, Heap 영역이 1MB~32MB이내의 고정된 크기로 2000여개 영역으로 분할되어있다. 이 고정 크기 부분의 영역을 Region이라고 부른다. 각 Region은 기존 JVM heap 영역이었던 New,Survivor,Old,Metaspace 영역을 각각 담당하지만, 동적으로 역할이 변경될 수 있다. 

 Region 안에 있는 객체들이, 다른 Region에 있는 객체들에 의해서 참조되는지를 관리하고, Region단위로 Live Object가 있는지 없는지를 판단하여 해당 Region이 다 차면, 살아있는 Object들을 다른 Region으로 copy한후, 해당 Region을 비우는 작업을 한다

Default GC

Java 7 - Parallel GC
Java 8 - Parallel GC
Java 9 - G1 GC
Java 10 - G1 GC


참고 및 출처: 

https://slenderankle.tistory.com/150 [SLENDER ANKLES's 개발블로그]

https://perfectacle.github.io/2019/05/07/jvm-gc-basic

https://d2.naver.com/helloworld/1329

https://mirinae312.github.io/develop/2018/06/04/jvm_memory.html

https://waspro.tistory.com/340

'개발 > JVM' 카테고리의 다른 글

JVM 기초  (0) 2020.01.19