카테고리 없음

Full GC 발생 원인 총정리

idea9329 2025. 12. 5. 15:03
728x90
반응형

Java 애플리케이션이 갑자기 멈추고 CPU가 치솟는 순간 대부분의 범인은 Full GC다. Full GC는 Young 영역이 아니라 Old 영역(또는 Metaspace·PermGen 포함 전체 힙) 을 정리하는, 가장 무거운 GC 작업이다. 아래 원인들을 알면 왜 Full GC가 터지는지 금방 파악할 수 있다.


1. Old 영역(Heap Old Generation) 메모리 부족

가장 흔한 이유.

  • 객체가 Young → Old로 계속 승격(tenured)되며 Old 영역이 가득 찰 때
  • GC가 Old 객체들을 치워도 빈 공간이 충분히 확보되지 않을 때
  • 메모리 누수(Leaking 객체)로 Old에 객체가 계속 쌓일 때

대표 상황

  • 캐시를 너무 크게 사용
  • 대용량 리스트/맵을 오래 유지
  • static 컬렉션에 데이터 계속 추가
  • 스레드 로컬(ThreadLocal) 누수

2. Young GC(=Minor GC)로 해결이 안 되는 경우

Young에서 Survivor로 이동 → 다시 Old로 이동 → Old가 빠르게 증가.

증상

  • API 응답은 처음엔 빠르지만 점점 느려짐
  • 힙 Old 영역 사용량이 꾸준히 상승 곡선을 그림

3. PermGen / Metaspace 부족 (클래스 메타데이터 영역)

Java 8 이전: PermGen
Java 8 이후: Metaspace

원인 예시

  • 동적 클래스 로딩 많음 (예: Spring 프록시, 리플렉션, Groovy, Nashorn, JSP 재컴파일)
  • OOM: Metaspace 발생 직전 Full GC 반복

4. System.gc() 호출

가장 의외이지만 매우 강력한 원인.

  • 개발 코드 또는 라이브러리에서 System.gc() 호출
  • 서버에 따라 JVM 옵션 -XX:+DisableExplicitGC 로 막지 않으면 Full GC 강제 실행됨

5. CMS / G1 등 특정 GC 알고리즘 특성

CMS

  • Concurrent Mode Failure → Full GC 강제
  • Old compaction이 불가하여 조각난 메모리(fragmentation) 해결 못함 → Full GC 발생

G1 GC

  • Mixed GC로 Old 정리 실패 시
  • Humongous Object가 많을 때

6. 대용량 객체 생성 (Humongous Objects)

예:

  • 1MB 이상의 배열
  • 대형 JSON, XML 파싱
  • Huge List 생성

대용량 객체는 단번에 Old 영역에 배치될 수 있어 Full GC를 유발한다.


7. Native Memory 부족

Java Heap 문제처럼 보이지만 실제 원인은 Native Memory 부족 → JVM이 Full GC를 유발해 메모리 회수 시도.

원인 예:

  • DirectByteBuffer 누수
  • Netty / nio buffer
  • Thread 너무 많이 생성

8. Heap이 과도하게 작게 설정됨

Heap 자체가 부족하면 정상적인 애플리케이션도 Full GC를 반복한다.

예:

-Xmx512m

처럼 너무 작게 설정됐을 때.


9. Stop-The-World(동시성 문제)로 인한 GC 지연 → Full GC 승격

GC 스레드 부족, CPU 포화로 인해 GC 타이밍을 놓치면 Full GC로 이어진다.


요약

Full GC 발생 3대 핵심 원인

  1. Old 영역 부족
  2. Metaspace 부족
  3. System.gc() 강제 호출

그리고 부가적인 메모리 누수, GC 알고리즘 특성, 대용량 객체 생성 등이 누적되면서 Full GC를 만든다.

728x90
반응형