과정을 즐기자

가비지 컬렉션(feat. Paralle GC, CMS GC, G1 GC) 본문

Java

가비지 컬렉션(feat. Paralle GC, CMS GC, G1 GC)

320Hwany 2023. 9. 14. 14:46

프로그래밍 언어는 메모리 관리 주체에 따라 크게 2가지로 나눌 수 있습니다. 

언어 자체적으로 메모리를 관리해주는 Managed 언어 (Java, C#)와 개발자가 직접 메모리를 관리하는

Unmanaged 언어 (C, C++)입니다.

Managed 언어는 메모리에 할당된 객체를 개발자가 관리를 하지 않아도 되고 Garbage Collector가 대신해줍니다.

이번 글에서는 Garbage Collection에 대해 알아보겠습니다.  

JVM 메모리 구조

Garbage Collector가 메모리의 어떤 부분을 관리해주는 지 알아보기 위해 먼저 JVM의 메모리 구조에 대해 알아보겠습니다.

JVM 메모리는 크게 5가지 영역으로 나뉩니다.

 

1. Method Area

Method Area에는 자바 컴파일러에 의해 변환된 바이트 코드가 저장되고 클래스 정보, static으로 선언한 변수 등이 있습니다.

 

2. Heap 

Heap 영역은 동적으로 생성된 객체가 저장되는 영역으로 바로 이 곳이 GC의 대상이 되는 영역입니다.

 

3. Stack

Stack 영역에는 지역변수, 매개변수, 메소드의 정보가 저장되는 영역입니다.

 

4. PC register

PC register는 쓰레드가 시작될 때 생성되며 현재 수행중인 JVM의 명령어를 저장하는 공간이며 쓰레드가 어떤 부분을

어떤 명령어로 수행할 지를 저장합니다.

 

5. Native Method Stack

Native Method Stack은 Java가 아닌 다른 언어로 작성된 코드를 위한 공간입니다.

 

여기서 GC의 대상이 되는 영역은 JVM 메모리의 Heap 영역입니다.

Heap 영역

Heap 영역은 위 그림과 같이 Young Generation, Old Generation으로 나눌 수 있습니다.

Young Generation은 다시 Eden, Survivor0, Survivor1로 나눌 수 있습니다.

Eden 영역은 새로 생성된 객체가 할당되는 영역이고 Survivol 영역은 최소 1번의 GC에서 살아남은 객체들이 할당되는 영역입니다.

 

이제 GC가 발생하는 상황을 살펴보겠습니다.

새로 생성된 객체들이 Eden 영역에 계속 할당됩니다. Eden 영역이 가득차게 되면 Minor GC가 발생합니다.

Minor GC가 발생하면 더이상 사용되지 않는 객체는 메모리가 해제됩니다.

여전히 사용되는 객체는 Minor GC에서 살아남아 Survivor0 영역으로 이동합니다.

이제 다시 새로 생성된 객체들이 Eden 영역에 할당되고 Eden 영역이 가득차게 되면 Minor GC가 발생하고

더 이상 사용되지 않는 객체는 메모리가 해제되며 여전히 사용되는 객체는 Survivor1 영역으로 이동합니다.

 

이렇게 Eden 영역이 가득찰 때마다 Minor GC가 발생하며 살아남은 객체들은 Survivor 영역으로 이동합니다.

Minor GC 과정에서 계속 살아남으면 age-bit 가 올라가는데 age-bit가 일정 숫자를 넘어가면 Old Generation으로 이동합니다.

 

이런 과정을 통해 Old Generation이 가득차면 Major GC가 발생합니다.

2가지 의문점

여기서 저는 2가지 의문점이 들었습니다.

첫 번째는 Young Generation과 Old Generation으로 나눈 이유가 궁금하였고

두 번째는 Survivor 영역도 왜 2개로 나누고 둘 중 하나는 항상 비운 상태를 유지해야 하는지가 궁금하였습니다.

 

Heap 영역을 Young Generation과 Old Generation으로 나눈 이유는 애플리케이션의 특성을 생각해보면 알 수 있습니다.

우선 대부분의 할당된 객체는 오랫동안 참조되지 않으며 금방 Garbage의 대상이 되며 오래된 객체는 새로운 객체로의 참조가 

거의 존재하지 않습니다. 그렇다면 Heap 영역 전체를 탐색할 것이 아니라 생성된지 얼마 되지 않은 객체들만 따로 구분한다면

훨씬 효율적일 것입니다. 따라서 Heap 영역을 크게 2개의 Generation으로 구분하였고 이에 따라 Young Generation을 대상으로

발생하는 Minor GC와 Old Generation을 대상으로 발생하는 Major GC로 나눌 수 있습니다.

 

그렇다면 Survivor을 2가지로 나눈 이유는 무엇일까요?

그냥 Survivor 영역 하나만 만들고 살아남은 객체는 age-bit 늘리고 살아남지 못한 객체는 지우면 되는 것 아닐까요?

만약 1개의 Survivor을 유지한다면 살아남지 못한 객체를 지우고 나서 메모리 파편화를 막기 위한 Compaction을 하는 비용이

발생합니다. Compaction 하는 비용이 다른 Survivor로 Copy하는 비용보다 더 크기 때문이라고 할 수 있습니다.

GC의 종류

이번에는 GC의 종류에 대해 알아보겠습니다.

GC의 종류에는 Serial GC, Paralle GC, Paralle Old GC, CMS GC, G1 GC 가 있습니다.

Serial GC

Serial GC는 하나의 쓰레드로 GC를 실행하여 애플리케이션을 중지하고 GC를 실행하는 Stop the world 시간이 깁니다.

거의 사용하지 않고 사용하더라도 CPU 코어가 1개인 경우에만 사용합니다.

Parallel GC

Paralle GC는 여러 개의 쓰레드로 GC를 실행합니다. Serial GC보다 Stop-The-World 시간이 훨씬 더 짧으며

Java 8의 기본 GC 방식입니다.

여기에 Paralle Old GC도 있는데 Old 영역까지 멀티 쓰레드 방식으로 동작한다는 차이가 있습니다.

CMS (Concurrent Mark Sweep) GC

CMS GC는 Stop-The-World 시간을 최소화 하여 GC 작업을 애플리케이션과 동시에 실행하려고 만들었습니다.

하지만 메모리와 CPU를 많이 사용하고 Mark-And-Sweep 과정 이후 메모리 파편화를 해결하는 Compaction이 

기본적으로 제공되지 않기 때문에 한계를 가집니다. G1 GC의 등장에 따라 Deprecated 되었습니다.

G1 (Garbage First) GC

G1 GC는 앞에서 소개한 다른 GC들과 다르게 Eden, Survivor, Old 영역이 고정된 크기를 갖지 않습니다.

전체 Heap 영역을 일정 크기의 Region으로 잘게 나누고 각 Region의 역할이 동적으로 변합니다.

이렇게 G1 GC는 런타임에 영역별 Region 개수를 튜닝할 수 있다는 장점이 있어 Stop-The-World 시간이 가장 짧습니다.

G1 GC는 Java 9 이상부터 기본 GC 방식입니다.

 

참고한 자료

 

[JVM GC] GC 종류와 동작 방식과 G1GC 튜닝 포인트

1. JVM GC 동작 순서 GC를 수행할 때에는 아래와 같이 Three-Step으로 이루어진다. (1) Heap 영역에 존재하는 객체들에 대하여 접근 가능 여부를 확인한다. (2) GC Root에서 시작하여 참조값을 따라가며 접

syhwang.tistory.com

 

[Java] Garbage Collection(가비지 컬렉션)의 개념 및 동작 원리 (1/2)

1. Garbage Collection(가비지 컬렉션)이란? [ Garbage Collection(가비지 컬렉션)이란? ] 프로그램을 개발 하다 보면 유효하지 않은 메모리인 가바지(Garbage)가 발생하게 된다. C언어를 이용하면 free()라는 함

mangkyu.tistory.com

 

G1GC Garbage Collector에 대해 알아보기 - 1

Java 9부터 Default로 설정된 가비지 컬렉터(Garbage Collector, GC)인 G1GC에 대해 알아봅시다. 2편에서는 G1GC 의 목적과 옵션에 대한 가이드를 제공하니 프로젝트에 적용해 보세요.

blog.leaphop.co.kr