
[[GC]]
GC 튜닝이 필요한 이유: [[STW (Stop The World)]]

- STW가 발생하면 [[GC]]를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춤.
- GC작업이 완료된 이후에야 중단했던 작업을 다시 시작됨.
- GC가 자주 발생하거나, 또는 시간이 오래 걸리는 경우는 어플리케이션이 비정상 동작하는 시간이 길어진다는 의미이기 때문에 대게의 경우 ==gc 튜닝이란 STW 시간을 줄이는 것을 의미==

### **GC 튜닝의 주의점**

그런데 GC 튜닝에 있어서 꼭 명심해야 하는 점이 있다.

**첫째는, GC 튜닝 옵션은 서비스의 특징 마다 적정 값이 다르다는 것이다.**

예를 들어 '누가 이 옵션값을 썼을 때 성능이 잘 나왔으니 우리도 이렇게 적용하자.' 라고 생각하면 절대 안 된다. 

왜냐하면 서비스 주제와 특징마다 생성되는 객체의 크기도 다르고 살아있는 기간도 다르기 때문이다. 

따라서 별도의 성능 모니터링을 통해 어느 지점에서 GC의 STW 문제가 나는지 **서비스마다 제각각 파악**하여 GC 튜닝을 진행할 필요가 있다.

**둘째는, GC 튜닝은 가장 마지막에 하는 작업이라는 것이다.**

GC 튜닝은 필요한 선행 지식과, 신경써야할 요소, 리스크에 비해서 얻어가는 부분이 너무 적기 때문에, GC를 건드리는 것보다 애플리케이션 코드로써 메모리 최적화를 더 신경 쓸것을 권장하는 의견도 있다.

GC 튜닝을 왜 하는지 근본적인 이유를 생각해보자.

일반적으로 Java에서 생성된 객체는 가비지 컬렉터가 처리해서 지운다.

즉, 생성된 객체가 많으면 많을수록 가비지 컬렉터가 처리해야 하는 대상도 많아지고, GC를 수행하는 횟수도 증가한다는 말이다. 그리고 GC의 수행 횟수가 늘어나면 STW 횟수도 많아지니 성능에 영향이 가게 된다.

따라서 GC 자체를 튜닝 하기 이전에 먼저 코드 단에서 **쓸모없는 객체 생성을 줄이는 리팩토링 작업을 먼저** 하는 것이 근본적인 해결법이 된다.

예를들어 ~~String~~ 대신 ~~StringBuilder~~나 ~~StringBuffer~~를 사용하는 거나, 로그를 최대한 적게 쌓도록 하는 등 임시 메모리를 적게 사용하도록 해주는 것이 먼저이다.

그리고 리팩토링 작업과 어플리케이션 메모리 조정을 해도 여전히 성능에 문제가 생기면 그제서야 GC 튜닝을 진행한다.

다시 말하자면 GC 튜닝은 자바 어플리케이션 성능 향상 작업에서 가장 마지막에 하는 작업이라는 것을 잊지 말자.

### **GC 튜닝의 목표**

**GC 튜닝**이란, 성능상 이슈를 일으키기 쉬운 GC에 대하여 최적화를 진행 하는 것을 말한다.

GC 튜닝의 목표의 핵심은 [[Minor GC]] 보다 Stop-The-Wold 시간이 긴 [[Major GC]]의 관리이다.

**첫째는, Old 영역으로 넘어가는 객체의 수 최소화하기 이다.**

위에서 살펴봤듯이, Old 영역의 크기는 Young(New) 영역의 크기보다 훨씬 거대하다.

따라서 Old 영역의 GC는 Young(New) 영역의 GC에 비해 상대적으로 시간이 오래 소요되기 때문에, 애초에 Old 영역으로 이동하는 객체의 수를 줄이면 Full GC가 발생하는 빈도를 많이 줄일 수 있게 된다.

이말은 즉, **Young(New) 영역의 크기를 잘 조절**하여 Old 영역으로 넘어가는 빈도를 줄이면 큰 효과를 볼 수 있다는 뜻이다.

**둘째는, Full GC 시간 줄이기 이다.**

Full GC의 실행 시간은 상대적으로 Minor GC에 비해 길기 때문에, Old 영역의 크기를 적절하게 설정하는 것도 하나의 방법이다.

그렇다고 Old 영역의 크기를 막 줄여버리면 자칫 OutOfMemoryError가 발생하거나 Full GC 횟수가 늘어날 수도 있다.

반대로 Old 영역의 크기를 늘리면 Full GC 횟수는 줄어들지만 실행 시간이 늘어나게 된다.

즉, GC 튜닝의 관건은 이 둘 사이를 잘 아우르는 적정 범위를 찾는 것이라 할 수 있다.