[JVM] GC 알고리즘 - Overview
자바에서 가비지 컬렉터는 대부분의 객체는 한번 쓰고 버려진다는 사실을 이용해서 설계되었다.
JVM에서 사용할 수 있는 가비지 컬렉터에는 여러 종류가 있다
모든 가비지 컬렉터는 힙을 별도의 제너레이션으로 나눠서 작업한다
Young 영 / Old 올드
영 제너레이션은 Eden 에덴과 Survivor Space 서바이버 스페이스로 나뉜다
모든 GC 알고리즘은 영 제너레이션에서 수집하는 동안 모든 어플리케이션 스레드를 중지시킨다.
매우 빨리 일어나는 작업이다.
객체는 처음 생성되면 먼저 힙의 영 제너레이션에 할당된다. 영 제너레이션이 가득차면 가비지 컬렉터는 모든 어플리케이션 스레드를 멈추고 영 제너레이션을 비운다. 더 이상 사용되지 않는 객체는 폐기되고 여전히 사용중인 객체는 어딘가로 옮겨진다.
Minor GC 장점
1) 영 제너레이션은 힙의 일부분이므로 전체 힙을 멈추지 않아도된다. 더 자주 중지되더라도 대체로 짧게 처리되는 것이 이득이다.
2) "어딘가로 옮겨진다" ==> 압축이 가능하다
객체가 올드 제너레이션으로 이동되면서 올드 제너레이션이 가득 찰 경우, JVM은 올드 제너레이션 내에서 더 이상 사용되지 않는 객체를 찾아서 폐기시킨다. 이 과정을 Full GC 라고 한다. Full GC가 일어나는 동안 일반적으로 어플리케이션 스레드가 오래 중지된다.
오래 중지 되지 않게 하려면 어떻게 할까?
처리는 더 복잡해지겠지만, 어플리케이션 스레드가 돌아가는 동안 가비지 컬렉을 할 수도 있다.
GC 알고리즘 중 CMS, G1이 이와 같은 방법을 사용한다.
이 둘은 Concurrent Collector 라고도 불린다.
CMS, G1을 사용하면 어플리케이션은 일반적으로 더 적게, 더 짧게 GC 로 인해 중지될 것이다.
하지만 어디나 트레이드오프는 있다. GC를 처리하기 위한 CPU 사용률이 더 늘어난다.
따라서 CPU를 100% 사용하는 배치 어플리케이션 같은 경우 CMS, G1을 사용할 경우 오히려 배치 작업이 느려질 수 있다. 하지만 CPU에 여분이 있다면, CMS, G1이 배치작업에서도 더 좋은 성능을 낸다.
CMS, G1도 물론 튜닝이 잘못된다면 긴 Full GC 중지가 일어날 수 있다.
-XX:+UseSerialGC
가장 단순하다. 힙을 처리하기 위해 단일 스레드를 사용한다. Minor, Full GC 가 일어나는 동안 모든 어플리케이션 스레드가 중지한다. Full GC가 발생하면 올드 제너레이션은 완전히 압축된다.
-XX:+UseParallelGC
영 제너레이션을 처리할 때 스레드를 여러개 사용한다. 때문에 Minor GC가 빠르다.
올드 제너레이션을 처리할 때도 여러개의 스레드를 사용할 수 있다. (-XX:+UseParallelOldGC)
Minor, Full GC가 일어나면 모든 어플리케이션 스레드를 멈춘다. Full GC는 올드제너레이션을 완전히 압축한다.
-XX:+UseParNewGC
Full GC 때 모든 어플리케이션이 멈추는 긴 중지 현상을 없애기 위해 설계됬다
Minor GC 는 모든 어플리케이션 스레드를 중지 시키고 여러 개의 스레드로 빠르게 처리한다.
CMS는 주기적으로 올드 제너레이션을 살피고 미사용 객체를 폐기하는데 하나 이상의 백그라운드 스레드를 사용한다.
어플리케이션 스레드는 Minor GC가 일어나는 동안에만 중지된다.
트레이드 오프
1) CPU 사용량이 증가한다. 백그라운드에서 GC 스레드가 돌아갈 정도로 충분한 CPU가 필요하다.
2) 힙의 단편화가 발생한다. 백그라운드 GC 스레드는 미사용 객체를 폐기하는 것이 전부이다. 사용하는 객체들만을 모아서 한곳으로 압축할 수는 없다. 단편화가 너무 심해지면 시리얼 컬렉터로 동작한다. 즉, 단일 스레드를 사용해서 올드 제너레이션을 비우고 압축하기 위해 모든 어플리케이션 스레드를 중단한다.
-XX:+UseG1GC
4GB 이상의 큰 힙을 가진 어플리케이션을 최소한으로 중지시키며 처리하도록 설계되었다.
Minor GC 는 모든 어플리케이션 스레드를 중지 시키고 여러 개의 스레드로 빠르게 처리한다.
백그라운드 GC 스레드로 올드 제너레이션을 처리한다.
단, CMS 와 다른점은 올드 제너레이션이 여러 영역으로 나뉘어져 있다.
때문에 G1은 올드 제너레이션의 한 영역에서 다른 영역으로 살아있는 객체를 복사하면서 압축시킬 수 있다. 때문에 힙의 단편화가 CMS보다 훨씬 덜 일어난다.
트레이드 오프 : CPU 사용량
무조건 좋은 GC 알고리즘은 없다. 사용하는 어플리케이션에 따라 선택하자.
시리얼 컬렉터 : 어플리케이션이 힙을 100MB미만으로 사용하는 경우 적합하다.
CPU가 넉넉한 경우, Throughput Collector 보다 CMS, G1이 처리율이 뛰어나다.
Throughput Collector가 보통 응답시간이 CMS, G1보다 빠르지만, Full GC 가 수행되면 당연히 응답시간은 느려진다.
CMS VS G1
4GB 보다 작은 힙에서는 CMS 가 더 빠를 가능성이 있다.
4GB 보다 큰 힙에서는 G1 을 사용하자
※ GC 강제로 일으키기 System.gc()
System.gc()를 사용하면 항상 Full GC를 수행하도록 한다.
이 메소드를 평소에 사용할 일은 없겠지만,
성능 모니터링을 할 때, 또는 어떠한 목적으로 JVM을 제대로 준비시키기 위해 사용될 수 있다.
'JAVA > JVM' 카테고리의 다른 글
[JVM] CMS Collector - GC Log (0) | 2021.12.16 |
---|---|
[JVM] Throughput Collector - 힙 사이즈 튜닝하기 (0) | 2021.12.16 |
[JVM] Throughput Collector - GC Log (0) | 2021.12.16 |
[JVM] 기본 GC 튜닝 (0) | 2021.12.16 |
[JVM] JIT 컴파일 로그, 컴파일 스레드, 인라이닝 튜닝 (0) | 2021.12.16 |
[JVM] JIT : Just In Time Compiler 개념 & 튜닝 (0) | 2021.12.16 |
[JVM] PERM 영역 이해하기 (0) | 2021.12.16 |
[JVM] CPU 사용률 , Run Queue 런큐 (0) | 2021.12.16 |