book/자바 최적화

[자바 최적화] GC 로깅, 모니터링, 튜닝, 툴

danuri 2023. 9. 5. 23:57

자바 최적화 책 정리

 

자바 최적화(Optimizing Java) | 벤저민 J. 에번스 - 교보문고

자바 최적화(Optimizing Java) | 자바 애플리케이션 성능을 한 단계 높여줄 튜닝 이야기성능 튜닝은 실험과학이다. 추측과 구전 튜닝에 의존할 일이 아니다. 이 책은 복잡한 기술 스택을 다루는 중/고

product.kyobobook.co.kr

 

GC 로깅 개요

GC 로깅 켜기

✅ GC 스위치

-Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintTenuringDistribution
-XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps

 

Flag Effect
-Xloggc:gc.log GC 이벤트에 로깅할 파일을 지정한다.
-XX:+PrintGCDetails GC 이벤트 세부 정보를 로깅한다.
-XX:+PrintTenuringDistribution 툴링에 꼭 필요한, 부가적인 GC 이벤트 세부 정보를 추가한다.
-XX:+PrintGCTimeStamps GC 이벤트 발생 시간을 (VM 시작 이후 경과한 시간을 초 단위로) 출력한다.
-XX:+PrintGCDateStamps GC 이벤트 발생 시간을 (벽시계 시간 기준으로) 출력한다.

-> GC 로깅은 오버헤드가 거의 없고 훌륭한 원천 정보이기 때문에 자바 애플리케이션이라면 필수로 GC 로그를 보관해야 한다.

 

GC 로그 vs JMX

✅ JMX(Java Management eXtension)

자바 애플리케이션의 모니터링과 관리기능을 제공하는 기술.

-> 파일로 기록되는 GC 로그와 달리 실시간으로 모니터링할 수 있다.

 

JMX의 단점

✅ 가비지 수집

수집기가 언제 실행될지 예측할 수 없기 때문에, GC 관련 데이터를 정확하게 분석할 수 없다.

 

✅ RMI(Remote Method Invocation)

JMX는 RMI를 기반으로 애플리케이션과 통신하기 때문에, 추가 부하가 발생한다.

 

GC 로그 데이터의 장점

✅ 가비지 수집

GC 과정에서 무슨 일이 발생했는지 정확히 파악하는데 유용하다.

논블로킹 쓰기를 하기 때문에 성능에 미치는 영향이 거의 없다.

-> 성능 튜닝 활동에서 절대 빠질 수 없다.

 


 

로그 파싱 툴

✅ GC 로그 메시지는 표준 포맷이 없다

심지어 포맷도 조금씩 계속 바뀐다.

-> 스스로 GC 로그를 파싱하지 말고 반드시 툴을 사용하자.

 

센섬

✅ jClarity사가 제작한 상용 메모리 분석기

GC 로그 파싱, 정보 추출, 자동 분석 기능을 제공한다.

-> OpenJDK 로깅 관련 소스를 낱낱이 분석해서, 그 어느 툴보다도 다양한 GC 로그 설정을 지원한다.

 

 

GCViewer

✅ GC 로그 파싱 및 그래프 출력

분석 기능은 없고 GC 로그 파싱만 할 수 있다.

 

 

같은 데이터를 여러 가지 형태로 시각화하기

✅ 툴마다 시각화 형태가 다르다

<센섬>

<GCViewer>

 

 


 

GC 기본 튜닝

✅ 성능 문제의 원인인 GC인가?

  • CPU 사용률이 100%에 가까운가?
  • 대부분의 시간(90%)이 유저 공간에서 소비되는가?
  • GC 로그가 쌓이가 있다면 현재 GC가 실행 중이라는 증거다.

-> 세 가지 조건이 다 맞는다면, GC가 성능 이슈를 일으키고 있을 가능성이 크다.

 

할당이란?

✅ 할당률을 줄여보자

1GB/s 이상으로 지속한다면 수집기 튜닝만으로는 해결할 수 없는 성능 문제가 터진 것이다.

-> 애플리케이션 할당 로직 리팩토링 필요.

 

✅ 덩치 큰 배열은 조기 승격될 가능성이 높다

객체가 너무 뚱뚱해서 에덴 영역에 안들어가면, 일찍 테뉴어드 영역으로 승격한다.

-XX:MaxTenuringThreshold=<n>

-> 테뉴어드 영역으로 승격되기 전까지 객체가 통과해야 할 가비지 수집 횟수

-> 한계치가 너무 낮으면 테뉴어드로 승격하는 객체가 많아지니 주의하자.

 

중단 시간이란?

✅ 중단 시간과 힙 크기에 대한 적절한 수집기

>1 s 1 s–100 ms <100 ms < 2 GB
Parallel Parallel CMS < 4 GB
Parallel Parallel/G1 CMS < 4 GB
Parallel Parallel/G1 CMS < 10 GB
Parallel/G1 Parallel/G1 CMS < 20 GB
Parallel/G1 G1 CMS > 20 GB

 

 

수집기 스레드와 GC 루트

✅ GC 루트 탐색 시간에 영향을 주는 요인

  • 애플리케이션 스레드 개수: 스레드 별로 스택을 탐색해야 한다.
  • 코드 캐시에 쌓인 컴파일드 코드량: JNI, JIT 컴파일드 코드에도 GC 루트가 있다.
  • 힙 크기: 힙이 크면 탐색 시간이 길어진다.

 

✅ 카드 테이블 탐색

올드 영역으로 넘어온 객체의 루트를 추적할 때 탐색

-> 보통 20GB 힙에서 카드 테이블은 2MB 정도 필요하고 이를 탐색하는 시간은 대략 10ms 정도이다.

 


 

Parallel GC 튜닝

✅ 튜닝이 단순한 수집기

플래그 작용
-XX:NewRatio=<n> (옛 플래그) 영 세대/전체 힙 비율
-XX:SurvivorRatio=<n> (옛 플래그) 서바이버 공간/영 세대 비율
-XX:NewSize=<n> (옛 플래그) 최소 영 세대 크기
-XX:MaxNewSize=<n> (옛 플래그) 최대 영 세대 크기
-XX:MinHeapFreeRatio (옛 플래그) 팽창을 막기 위한 GC 이후 최소 힙 여유 공간 비율(%)
-XX:MaxHeapFreeRatio (옛 플래그) 수축을 막기 위한 GC 이후 최대 힙 여유 공간 비율(%)

-> 사람보다 프로그램이 크기를 알아서 잘 결정하기 때문에, 명시적으로 크기를 설정하는 일은 삼가는게 좋다.

 


 

CMS 튜닝

✅ 튜닝이 까다로운 수집기

CMS는 중단 시간을 줄이기 위한 여러 가지 복잡성을 가지고 있다.

-> CMS 플래그 값을 바꾸는 것에 대해 단순하게 생각하면 안된다.

그럼에도 불구하고 CMS 튜닝을 감행해야 한다면 다음 플래그를 참고하자.

-XX:ConcGCThreads=<n> // GC에 할당된 코어 수 조정 (애플리케이션 처리율을 늘리고 GC 속도를 낮춘다)
-XX:CMSInitiatingOccupancyFraction=<n> // CMS가 힙이 얼마나 찾을 때 수행할지 조정
-XX:+UseCMSInitiatingOccupancyOnly // 앞서 설정한 여유공간을 동적으로 조정하는 기능을 off한다

 

 

 

단편화로 인한 CMF

✅ 프리 리스트 통계 확인

CMS가 관리하는 프리 리스트로 인해 단편화가 발생하고, 나아가 CMF의 위험이 있다.

-XX:PrintFLSStatistics=1

-> 해당 스위치를 통해 GC 로그에 프리 리스트 관련 정보를 표시할 수 있다.

 


 

G1 튜닝

✅ G1도 CMS 처럼 옵션이 꽤 많다

튜닝이 어떤 영향을 미칠지 알아차리기가 어렵다.

-> 그래도 튜닝해야 할 경우 다음 스위치를 지정하자.

-XX:+UnlockExperimentalVMOptions

 

애플리케이션 할당률이 계속 높은 상태로 대부분 단명 객체가 생성되고 있다면 다음 튜닝을 고려해보자.

  • 영 세대를 크게 설정한다.
  • 테뉴어드 한계치를 최대 15 정도로 늘려 잡는다.
  • 애플리케이션에서 수용 가능한 최장 중단 시간 목표를 정한다.

 


 

 

jHiccup

✅ JVM이 연속적으로 실행되지 못한 지점을 보여주는 계측 도구

ex) GC STW 중단

+) jHiccup은 HdrHistogram의 입력 데이터로 사용 가능한 결과를 출력한다.

 

jHiccupLogProcessor -i hiccup-example2.hlog -o alloc-example2

-> 위와 같은 간단한 명령으로 다음 그래프를 얻을 수 있다.

 

 

HdrHistogram과 jHiccup 세부 내용 참고