서버 메모리 · CPU 최적화 (Java 21 GC 튜닝 포함)
애플리케이션 성능은 DB나 API 구조뿐 아니라, 서버 내부에서 발생하는 메모리 관리와 GC(Garbage Collection)에도 크게 영향을 받는다.
특히 고트래픽 환경에서는 GC 중단 시간(STW)과 메모리 사용량이 시스템 지연의 직접적인 원인이 된다.
이 글에서는 Java 21 + Spring Boot 3.x 환경에서 실무적으로 활용 가능한 메모리·CPU 최적화 전략을 정리한다.
#Java 21의 GC 기본 이해
Java 21에서는 G1 GC가 기본이며, 서버 환경에서는 ZGC도 도입이 활발해지고 있다.
두 GC 모두 “Stop The World 시간을 최소화하는 것”을 목표로 한다.
G1 GC 특징 (기본값)
- 짧은 STW
- 적당한 메모리 소비
- 대부분의 서비스에 적합한 범용 GC
ZGC 특징 (저지연 GC)
- STW 시간이 거의 1ms 미만
- 대규모 메모리(수 GB ~ 수십 GB) 환경에서 우수
- GC 일시중단을 최소화해야 하는 고급 서비스에 적합
일반 웹 서비스 → G1 GC 유지
고성능/대용량/저지연 서비스 → ZGC 고려
#메모리 최적화 전략
1) 불필요한 객체 생성 줄이기
메모리 병목의 가장 흔한 원인은 불필요한 객체 생성이다.
Spring Boot 서비스에서 특히 다음 패턴이 위험하다:
- 매 요청마다 ObjectMapper 생성
- DTO 변환 시 임시 객체 과다 생성
- Stream API 남용으로 박싱/언박싱 증가
- 대용량 컬렉션을 계속 새로 생성
개선 방법
- ObjectMapper는 싱글톤으로 유지
- DTO는 불변 record 사용
- Streams → 기본 for문으로 교체 (대량 처리 시)
- List 초기 용량 지정
#CPU 최적화 전략
CPU는 주로 직렬화/역직렬화, 암호화, 반복 계산, 대량 루프 등에서 소모된다.
특히 JSON 직렬화는 CPU 비중이 매우 크기 때문에 최적화 효과가 크다.
1) JSON 직렬화 비용 감소
- 필요 이상의 필드 직렬화 금지
- snake_case 변환 비활성화
- record 기반 DTO 사용
2) 암호화/해싱 비용 절약
비밀번호 암호화, JWT 서명, 해싱 등은 CPU를 많이 사용한다. 대량 요청에서는 반드시 다음을 고려해야 한다.
- BCrypt 대신 Argon2나 scrypt로 마이그레이션
- 해싱 비용(cost factor)를 서비스 규모에 맞게 조정
- 서명 재검증 최소화
3) 불필요한 반복 처리 제거
- List 연속 정렬 금지
- 중복 반복 조회 제거
- 루프 내부에서 DB or Redis 접근 금지
#GC 튜닝 전략
Java 21에서는 GC 튜닝 난이도가 낮아졌지만, 기본값만으로 완벽하진 않다. 특히 트래픽이 많은 API에서는 GC 튜닝이 필요하다.
1) 힙 사이즈 조정
힙 사이즈는 너무 크거나 작으면 오히려 성능이 떨어진다.
-Xms2g -Xmx2g
초기 힙과 최대 힙을 동일하게 두는 것이 일반적이다.
2) G1 GC 튜닝 옵션
-XX:MaxGCPauseMillis=200
-XX:+UseStringDeduplication
- Pause 시간을 200ms 이하로 목표 설정
- 문자열 중복 제거로 메모리 절약
3) ZGC 사용 시
ZGC는 설정이 매우 단순하다:
-XX:+UseZGC
대규모 메모리 환경(8GB 이상) 또는 매우 짧은 지연 시간이 필요한 API에 적합하다.
#메모리 누수 방지 전략
1) 스레드 로컬(ThreadLocal) 누수 방지
ThreadLocal은 제거하지 않으면 메모리 누수의 가장 큰 원인이다.
특히 Virtual Thread 도입 후 더욱 조심해야 한다.
- 사용 후 반드시 remove()
- ThreadLocal 기반 캐싱 금지
- Virtual Thread 환경에서는 ThreadLocal 사용 최소화
2) 캐시 과사용 주의
- TTL 없는 캐시는 메모리 누수의 1순위
- 대형 리스트 캐싱 금지
- 조건 기반 캐싱 시 키 폭발(Key Explosion) 주의
3) 대형 객체(Big Object) 생성 금지
한 번에 1MB 이상 객체 생성은 GC 효율을 급격히 떨어뜨린다.
- 대형 문자열 결합 방지
- 대형 JSON 직렬화 금지
- 대량 데이터는 스트리밍 처리
마치며
서버 성능은 코드만이 아니라 JVM 내부 구조와 GC에 의해 크게 좌우된다.
Java 21은 G1과 ZGC의 성능이 개선되어 이전보다 훨씬 안정적으로 동작하지만,
적절한 힙 설정, 객체 생성 감소, GC 튜닝을 함께 사용해야 진정한 최적화를 달성할 수 있다.
다음 글에서는 트래픽 급증 대비 아키텍처 패턴 (Rate Limit · Circuit Breaker · Bulkhead)을 다룬다.
장애 대비를 위한 필수적인 안정화 전략들을 실전 중심으로 정리할 예정이다.
'TIL' 카테고리의 다른 글
| 11/4 (0) | 2025.11.04 |
|---|---|
| Spring Boot 성능 최적화 7 (0) | 2025.11.03 |
| Spring Boot 성능 최적화 5 (0) | 2025.10.30 |
| Spring Boot 성능 최적화 4 (0) | 2025.10.29 |
| Spring Boot 성능 최적화 3 (0) | 2025.10.28 |