운영

[운영] JVM 메모리 설정, 왜 중요할까?

ioh'sDeveloper 2025. 3. 12. 12:44

JVM 힙 메모리 크기 개념 정리 및 실무 적용 사례

서론: JVM 메모리 설정, 왜 중요할까?

JVM 기반의 애플리케이션을 운영하다 보면 OutOfMemoryError(OOM) 가 발생하거나, GC(Garbage Collection) 튜닝이 필요한 경우가 많다.
이럴 때 JVM 메모리 구조를 제대로 이해하고 적절한 설정을 하면 애플리케이션 성능 최적화안정적인 운영이 가능하다.

이번 포스팅에서는 JVM 힙 메모리 개념과 설정 방법을 실무 경험을 바탕으로 정리하고, 적절한 메모리 설정값과 실무 적용 사례를 공유하려 한다.


1. JVM 메모리 구조 살펴보기

JVM이 사용하는 메모리는 크게 다음과 같이 구분할 수 있다.

메모리 영역 역할 및 설명

Heap 애플리케이션이 생성하는 객체 저장 공간 (-Xms, -Xmx 로 설정)
Stack 각 쓰레드별 메서드 호출 스택 (-Xss 로 설정)
Metaspace 클래스 메타데이터 저장 (-XX:MaxMetaspaceSize 로 설정)
Code Cache JIT(Just-In-Time) 컴파일된 네이티브 코드 저장
Direct Memory 네이티브 메모리 (ByteBuffer.allocateDirect() 사용 시 할당)

이 중에서 Heap 메모리는 애플리케이션 성능에 가장 큰 영향을 미치며, GC와 밀접한 관계가 있다.


2. JVM이 전체 서버 메모리를 다 사용하지 않는 이유

1) OS와 기타 프로세스가 메모리를 사용해야 한다

예를 들어, 서버에 4GB RAM이 있다고 가정하면, JVM이 이를 전부 사용하면 안 된다.
OS가 동작하기 위해서 일정량의 메모리를 사용해야 하고, 기타 네트워크 프로세스나 파일 시스템 캐시도 메모리를 차지한다.

2) JVM은 Heap 외에도 여러 메모리 영역을 사용한다

  • Heap 외에도 Stack, Metaspace, Code Cache, Direct Memory 등이 존재하며, 전체 JVM 메모리 사용량은 Heap보다 크다.
  • 따라서 Heap 크기(-Xmx)만 보고 JVM 전체 메모리를 판단하면 안 된다.

3) GC가 힙 메모리를 동적으로 관리한다

  • JVM은 모든 힙 메모리를 한 번에 사용하지 않고, 필요할 때 확장하는 방식으로 동작한다.
  • -Xmx4g로 설정했다고 해서 항상 4GB를 사용하는 것이 아니라, GC가 필요할 때만 사용량이 증가한다.

3. 적절한 JVM 메모리 설정 방법

서버 환경과 애플리케이션 특성에 따라 JVM 메모리 크기를 적절히 설정해야 한다.
다음은 서버의 물리 메모리에 따른 적절한 JVM 설정값이다.

(1) 서버 메모리가 4GB일 경우

-Xms2g -Xmx2g
-XX:MaxMetaspaceSize=256m
-Xss1m
-XX:MaxDirectMemorySize=256m
  • Heap은 전체 메모리의 약 50% (2GB)
  • Metaspace는 기본적으로 256MB 정도 설정
  • Stack, Direct Memory도 적절히 설정하여 메모리 낭비 방지

(2) 서버 메모리가 8GB일 경우

-Xms4g -Xmx4g
-XX:MaxMetaspaceSize=512m
-Xss1m
-XX:MaxDirectMemorySize=512m
  • Heap을 4GB로 설정하여 GC 부담을 줄임
  • Metaspace와 Direct Memory도 증가

(3) 서버 메모리가 16GB 이상일 경우

-Xms8g -Xmx8g
-XX:MaxMetaspaceSize=1g
-Xss1m
-XX:MaxDirectMemorySize=1g
  • Heap을 8GB로 설정하여 안정적인 성능 유지
  • GC 튜닝 필요 시 G1GC, ZGC 등의 GC 옵션 고려 가능

4. GC 튜닝 및 추가 설정

메모리 설정뿐만 아니라 GC(Garbage Collection) 방식 선택도 중요하다.

1) GC 옵션 추천

  • Java 8 이상 → -XX:+UseG1GC (대부분의 애플리케이션에 적합)
  • Java 11 이상 → -XX:+UseZGC or -XX:+UseShenandoahGC (낮은 레이턴시 필요 시)

2) GC 로그 설정

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/gc.log
  • GC 로그를 저장하고 분석하여 최적의 Heap 크기를 설정 가능

3) OOM(OutOfMemoryError) 방지를 위한 설정

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path/to/dump
  • OOM 발생 시 Heap Dump를 저장하여 원인 분석 가능

5. 실무 적용 사례: JVM 메모리 설정으로 성능 최적화

🔹 문제 상황: 빈번한 GC와 성능 저하

어떤 애플리케이션에서는 JVM Heap이 너무 작게 설정되어 있어 빈번한 GC 발생으로 성능 저하가 발생했다.
기존 설정:

-Xms512m -Xmx1g

문제점:

  • 힙이 작아 객체 할당과 GC가 반복됨 → CPU 사용률 증가
  • GC 로그를 확인하니 Full GC가 자주 발생

✅ 해결 방법: 적절한 Heap 크기 설정

-Xms4g -Xmx4g
-XX:+UseG1GC
  • Heap을 4GB로 늘려 불필요한 GC 발생을 줄임
  • G1GC를 사용하여 GC 지연시간을 최소화
  • 결과: CPU 사용률 감소, 애플리케이션 응답 속도 개선

6. 결론 및 정리

💡 JVM 메모리 설정 핵심 요약

  • Heap 크기는 서버 메모리의 50~70%가 적당 (-Xmx 설정)
  • Metaspace, Stack, Direct Memory도 함께 고려해야 함
  • GC 튜닝(G1GC, ZGC 등)을 활용하면 성능 최적화 가능
  • GC 로그를 분석하면서 최적의 설정값을 찾는 것이 중요

마무리하며…

JVM의 메모리 설정은 단순한 -Xmx 값 조정이 아니라, 애플리케이션의 메모리 사용 패턴과 GC 튜닝을 함께 고려해야 한다.
실무에서는 항상 GC 로그를 모니터링하면서 적절한 설정을 찾는 과정이 중요하다.

이 글이 JVM 메모리 최적화에 도움이 되었기를 바라며, 추가적인 경험과 의견이 있다면 댓글로 공유해주면 좋겠다!