[JVM] CMS Collector - 힙 사이즈 / Concurrent Mode 튜닝하기

2021. 12. 16. 15:07 JAVA/JVM

CMS 힙 크기 튜닝하기
CMS는 힙과 제너레이션의 크기를 결정하기 위해 Throughput Collector에서 봤던
플래그 MaxGCPauseMillis=N , GCTimeRatio=N 두개를 사용한다.

[JVM] Throughput Collector - 힙 사이즈 튜닝하기

CMS Concurrent Mode 튜닝하기
CMS를 튜닝할 때 가장 중요한 것은 Full GC 가 발생하지 않도록 하는 것!
CMS는 Full GC가 발생하지 않는것이 가장 이상적이다

CMS의 영 제너레이션은 Full GC 가 발생하지 않으면 절대로 크기가 변경되지 않는다
CMS의 목표는 Full GC가 발생하지 않는 것이므로,
잘 튜닝된 CMS 어플리케이녀은 절대로 영 제너레이션의 크기가 변경되지 않는다. 

CMS 올드 제러네이션이 디폴트 70% 까지 차면 Concurrent Mode가 시작되고,
백그라운드 스레드는 가비지를 찾기 위해 올드 제너레이션을 검사한다

CMS는 올드 제너레이션의 남은 30%가 차서 Full GC가 발생하기 전에,
병렬 가비지 컬렉을 완료해야 한다. 그렇지않으면 Full GC가 발생한다.

이러한 상황을 피하기 위해 CMS를 튜닝할 수 있는 방법은 다음과 같다
1) 힙 크기 / 올드 제너레이션의 크기 늘리기
2) 백그라운드 스레드 일찍 수행하기
3) 백그라운드 스레드 많이 사용하기

1) 힙크기 / 올드 제너레이션의 크기 늘리기
가장 쉽고 좋은 해결책은 1) 힙 크기를 늘리는 것이다.  힙 크기를 늘릴 수 없다면 스레드의 동작방식을 바꾸자. 

2) 백그라운드 스레드 일찍 수행하기
CMS가 동시병렬을 시작하는 기본 시작점이 올드제너레이션의 70%가 찼을때였다. 이 비율을 플래그로 바꿀 수 있다.
70%가 아닌 50%에서 수행하면 동시병렬 모드가 실패해서 Full GC가 생길 확률이 줄어들 것이다.

-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=N (Default : 70 %)

UseCMSInitiatingOccupancyOnly 플래그를 먼저 명시해야한다.
그렇지 않으면 CMSInitiatingOccupancyFraction플래그가 사용되지 않고, 다른 복잡한 방법을 사용한다. 

CMSInitiatingOccupancyFraction=N의 최적의 값을 찾아내려면??
병렬 모드 실패 로그를 찾은 다음, 그 전에 가장 최근에 시작된 CMS로그를 찾는다.
CMS Initial-Mark 단계의 로그를 보면, 병렬 모드 실패하기 전 올드 제너레이션의 크기를 알 수 있다.
아래 로그의 경우, 올드 제너레이션의 크기가 50%찼을 때 CMS가 시작된 것을 알 수 있다.
결국 N 값을 50보다 낮게 줘야 할 것이다.
( 디폴트 70%가 적용되지 않은 이유는, UseCMSInitiatingOccupancyOnly를 명시하지 않아서)

3) 백그라운드 스레드 많이 사용하기
-XX:ConcGCThreads = N = (3+ParallelGCThreads) / 4
ConcGCThreads 플래그를 설정하면 ParallelGCThreads 병렬 스레드의 개수가 설정된다.
ConcGCThreads 가 1일 경우 병렬 스레드는 1~4개, 2일 경우 5~8개까지 병렬 스레드가 증감한다는 의미이다. 

CPU가 여유로울 경우에만 사용할 것!