(Java) Garbage Collection 튜닝
GC 튜닝을 꼭 해야 할까?
본격적으로 GC 튜닝을 살펴보기 전에 다음 질문에 대해 생각해 보자.
"모든 Java 기반의 서비스에서 GC 튜닝을 해야 할까?"
결론부터 이야기하면 모든 Java 기반의 서비스에서 GC 튜닝을 진행할 필요는 없다.
GC 튜닝이 필요 없다는 이야기는 운영 중인 Java 기반 시스템의 옵션과 동작이 다음과 같다는 의미이다.
- -Xms 옵션과 –Xmx 옵션으로메모리크기를지정했다.
- -server 옵션이포함되어있다.
- 시스템에 Timeout 로그와같은로그가남지않는다.
다시 말하면, 메모리 크기도 지정하지 않고 Timeout 로그가 수도 없이 출력된다면 여러분의 시스템에서 GC 튜닝을 하는 것이 좋다.
그런데 한 가지 꼭 명심해야 하는 점이 있다. GC 튜닝은 가장 마지막에 하는 작업이라는 것이다.
GC 튜닝을 하는 이유가 무엇인지 근본적인 원인을 생각해 보자. Java에서 생성된 객체는 가비지 컬렉터(Garbage Collector)가 처리해서 지운다. 생성된 객체가 많으면 많을수록 가비지 컬렉터가 가 처리해야 하는 대상도 많아지고, GC를 수행하는 횟수도 증가한다. 즉, 여러분이 운영하고 만드는 시스템이 GC를 적게 하도록 하려면 객체 생성을 줄이는 작업을 먼저 해야 한다.
"티끌 모아 태산"이라는 말이 있듯이, String대신 StringBuilder나 StringBuffer를 사용하는 것을 생활화하는 것부터가 시작이라고 보면 된다. 그리고, 로그를 최대한 적게 쌓도록 하는 것이 좋다. 하지만 어쩔 수 없는 현실도 있다. 경험상 XML과 JSON 파싱은 메모리를 가장 많이 사용한다. 아무리 String을 최대한 사용 안 하고 Log 처리를 잘 하더라도, 10~100 MB짜리 XML이나 JSON를 파싱하면 엄청난 임시 메모리를 사용한다. 그렇다고 XML과 JSON을 사용하지 않기는 어렵다. 그냥 현실이 그렇다는 것만 알아주기 바란다.
만약 애플리케이션 메모리 사용도 튜닝을 많이 해서 어느 정도 만족할 만한 상황이 되었다면, 본격적으로 GC 튜닝을 시작하면 된다. 필자는 GC 튜닝의 목적을 두 가지로 나눈다. Old 영역으로 넘어가는 객체의 수를 최소화하는 것과 Full GC의 실행 시간을 줄이는 것이다.
Old 영역으로 넘어가는 객체의 수 최소화하기
JDK 7부터 본격적으로 사용할 수 있는 G1 GC를 제외한, Oracle JVM에서 제공하는 모든 GC는 Generational GC이다. 즉, Eden 영역에서 객체가 처음 만들어지고, Survivor 영역을 오가다가, 끝까지 남아 있는 객체는 Old 영역으로 이동한다. 간혹 Eden 영역에서 만들어지다가 크기가 커져서 Old 영역으로 바로 넘어가는 객체도 있긴 하다. Old 영역의 GC는 New 영역의 GC에 비하여 상대적으로 시간이 오래 소요되기 때문에 Old 영역으로 이동하는 객체의 수를 줄이면 Full GC가 발생하는 빈도를 많이 줄일 수 있다. Old 영역으로 넘어가는 객체의 수를 줄인다는 말을 잘못 이해하면 객체를 마음대로 New 영역에만 남길 수 있다고 생각할 수 있지만, 그렇게는 할 수는 없다. 하지만 New 영역의 크기를 잘 조절함으로써 큰 효과를 볼 수는 있다.
댓글
댓글 쓰기