[JAVA] 가비지 컬렉션 동작 원리와 모니터링 방법
Java 애플리케이션의 성능을 최적화하기 위해서는 가비지 컬렉션(GC)의 동작 원리를 이해하고 적절히 모니터링하는 것이 중요하다.
이 글에서는 GC의 기본 개념부터 실전 모니터링 방법까지 자세히 알아본다.
JVM 메모리 구조
JVM 메모리는 크게 다음과 같이 구분된다:
Heap 영역
[Young Generation]
- Eden Space
- Survivor Space 0
- Survivor Space 1
[Old Generation]
- Tenured Space
Non-Heap 영역
- Metaspace (Java 8+)
- Code Cache
- Thread Stacks
각 영역의 특징
- Young Generation
- 새로 생성된 객체가 할당되는 영역
- Minor GC가 발생하는 영역
- 대부분의 객체가 빠르게 사라짐
- Old Generation
- 오래 살아남은 객체가 이동하는 영역
- Major GC가 발생하는 영역
- GC 시간이 더 오래 걸림
- Metaspace
- 클래스 메타데이터 저장
- Java 8부터 PermGen을 대체
- 네이티브 메모리 사용
GC 알고리즘 비교
Serial GC
-XX:+UseSerialGC
- 단일 스레드로 GC 수행
- 간단하지만 성능이 제한적
- 적은 메모리와 CPU 코어에 적합
Parallel GC
-XX:+UseParallelGC
- 다중 스레드로 GC 수행
- 처리량(Throughput) 중시
- 대규모 배치 작업에 적합
CMS GC (Concurrent Mark Sweep)
-XX:+UseConcMarkSweepGC # Java 9부터 deprecated
- 애플리케이션 스레드와 동시 실행
- 짧은 일시 정지 시간
- 메모리와 CPU 사용량이 높음
G1 GC (Garbage First)
-XX:+UseG1GC # Java 9부터의 기본 GC
- 영역을 작은 단위로 나눠서 관리
- 예측 가능한 일시 정지 시간
- 대용량 힙 메모리에 적합
ZGC (Java 11+)
-XX:+UseZGC
- 초저지연 GC
- 테라바이트 급 힙 처리 가능
- 일시 정지 시간 10ms 미만
GC 튜닝 팁
1. 힙 크기 설정
-Xms4g # 초기 힙 크기
-Xmx4g # 최대 힙 크기
2. Young Generation 크기 조정
-XX:NewRatio=2 # Old:Young = 2:1
-XX:NewSize=2g # Young 영역 초기 크기
-XX:MaxNewSize=2g # Young 영역 최대 크기
3. GC 로깅 활성화
-Xlog:gc*:file=gc.log:time,uptimemillis:filecount=5,filesize=100m
4. 모니터링 지표 설정
// JMX를 통한 모니터링 설정
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.authenticate=false
GC 로그 분석 방법
1. 기본 GC 로그 형식
[2023-11-14T10:15:30.123+0900] GC(100) Pause Young (Normal) (G1 Evacuation Pause)
2. 주요 분석 포인트
- GC 발생 빈도
- GC 소요 시간
- 메모리 회수량
- Full GC 발생 여부
3. 로그 분석 도구
# GCViewer 실행
java -jar gcviewer.jar gc.log
# jstat 사용
jstat -gc <pid> 1000
실전 모니터링 예제
1. JVM 상태 모니터링
public class GCMonitoring {
public static void getGCStats() {
List<GarbageCollectorMXBean> gcBeans =
ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
System.out.println("GC Name: " + gcBean.getName());
System.out.println("Collection count: " +
gcBean.getCollectionCount());
System.out.println("Collection time: " +
gcBean.getCollectionTime() + "ms");
}
}
}
2. 메모리 사용량 모니터링
public class MemoryMonitoring {
public static void getMemoryStats() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
System.out.println("Init Heap: " +
heapUsage.getInit() / 1024 / 1024 + "MB");
System.out.println("Used Heap: " +
heapUsage.getUsed() / 1024 / 1024 + "MB");
System.out.println("Max Heap: " +
heapUsage.getMax() / 1024 / 1024 + "MB");
}
}
문제 해결 시나리오
1. 높은 GC 부하
증상: GC가 너무 자주 발생
해결: Young Generation 크기 증가
-XX:NewRatio=3
2. Full GC 빈발
증상: Full GC가 자주 발생
해결: Old Generation 크기 조정
-XX:CMSInitiatingOccupancyFraction=75
3. 긴 GC 일시정지
증상: GC 일시정지 시간이 김
해결: G1 GC로 전환 및 목표 일시정지 시간 설정
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
모니터링 체크리스트
- 일간 체크항목
- GC 발생 빈도
- 메모리 사용량 추이
- Full GC 발생 여부
- 주간 체크항목
- GC 시간 추이 분석
- 메모리 누수 징후 확인
- 힙 덤프 분석
- 월간 체크항목
- GC 설정 최적화 검토
- 성능 지표 리포트 작성
- 시스템 확장 계획 수립
'개발&프로그래밍' 카테고리의 다른 글
[JAVA] 효과적인 예외 처리 전략 (0) | 2024.11.16 |
---|---|
[JAVA] Java의 String Pool과 문자열 최적화 (2) | 2024.11.15 |
[IntelliJ IDEA] 코드 리팩토링을 도와주는 플러그인 TOP 5 (0) | 2024.11.05 |
[JAVA] try-with-resources와 AutoCloseable 인터페이스 (0) | 2024.11.04 |
[JAVA] 직렬화(Serializable)와 역직렬화 (6) | 2024.11.03 |
댓글