Java metaspace 사용량이 높을 때 무엇부터 볼까
마지막 업데이트

Java metaspace 사용량이 높을 때 무엇부터 볼까


Java metaspace 사용량이 계속 오른다면, heap 문제와 같은 눈으로 보면 시간이 오래 걸립니다. 먼저 무엇이 class metadata를 계속 추가하거나 붙잡고 있는지 봐야 합니다.

그래서 metaspace 장애는 일반 메모리 장애와 결이 다릅니다. heap 문제는 객체 lifetime 쪽이 더 중요하지만, metaspace 문제는 class loading 동작, classloader lifecycle, generated class, 배포 패턴이 metadata를 얼마나 오래 살게 하는지가 핵심입니다.

이 글은 실전 순서에 집중합니다.

  • 실제 압박이 metaspace인지 heap인지 어떻게 확인할지
  • class loading, generated class, classloader churn에서 무엇을 먼저 볼지
  • 배포와 reload 동작이 오래된 metadata를 어떻게 남기는지

짧게 말하면 먼저 metaspace 압박이 맞는지 확인하고, 그다음 최근 classloading 증가, generated class 동작, classloader lifecycle을 본 뒤, 곧바로 MaxMetaspaceSize만 키우는 쪽으로 가지 않는 편이 좋습니다.

더 넓은 Java 분기부터 다시 보고 싶다면 Java 트러블슈팅 가이드로 가세요.


먼저 classloading churn부터 보기

metaspace 문제는 보통 business data가 아니라 class metadata 증가에서 시작됩니다.

그래서 일반 객체 allocation보다 classloading 동작이 더 중요합니다.

이 첫 분기가 핵심입니다.

  • heap이 주된 압박이면 object retention과 allocation을 봐야 함
  • metaspace가 주된 압박이면 어떤 class가 계속 로드되거나 retained되는지 봐야 함

이 분기 없이 보면 heap graph와 cache 코드만 오래 보다가, 실제 문제인 class metadata lifecycle을 놓치기 쉽습니다.


metaspace 압박은 lifecycle 문제인 경우가 많다

metaspace는 보통 아래 중 하나 때문에 계속 커집니다.

  • 새 class가 계속 생성됨
  • classloader가 반복적으로 생성됨
  • 오래된 classloader가 해제되지 않음
  • 배포나 reload 동작이 metadata를 오래 붙잡음

그래서 metaspace 문제는 business traffic 그 자체보다 런타임 구조 문제인 경우가 많습니다.

더 유용한 질문은 “메모리가 왜 높은가?”보다 “왜 class metadata가 계속 늘거나 여전히 reachable한가?”입니다.


자주 나오는 원인

1. 반복적인 classloader 생성

reload 패턴이나 custom loading 경로가 오래된 class metadata를 남길 수 있습니다.

자주 보이는 예시는:

  • 반복적인 plugin loading
  • 장수 프로세스에 남아 있는 hot reload 성격의 동작
  • 프레임워크나 컨테이너가 새로운 classloader를 계속 만드는 경우

오래된 classloader가 reachable 상태면, 그 classloader가 가진 class도 같이 reachable 상태로 남습니다.

2. dynamic proxy와 generated class 증가

proxy-heavy framework나 runtime code generation이 metaspace를 예상보다 빨리 키울 수 있습니다.

특히 아래가 의심됩니다.

  • proxy 기반 프레임워크
  • bytecode generation 라이브러리
  • 설정 변화에 따라 generated class가 계속 생기는 경로

이 경우 한 번의 명확한 leak보다, 끝없이 flatten되지 않는 class generation 흐름이 문제인 경우가 많습니다.

3. 배포 churn과 release 미비

장수 프로세스에서 반복적인 재구성이나 배포가 metadata를 의도보다 오래 붙잡을 수 있습니다.

특히 아래 패턴이 수상합니다.

  • 같은 프로세스가 여러 설정 변경을 계속 살아서 겪음
  • 오래된 애플리케이션 모듈이 교체됐지만 완전히 release되지 않음
  • 사용자 트래픽보다 배포/재설정 이후 metaspace가 더 민감하게 증가함

이 패턴은 일반 heap 문제보다 classloader lifecycle 문제를 더 강하게 가리킵니다.


실전 점검 순서

metaspace가 계속 오를 때는 아래 순서가 가장 도움이 됩니다.

  1. 실제 압박이 metaspace인지 heap인지 확인
  2. 최근 classloading churn 확인
  3. proxy / generated class 동작 확인
  4. classloader lifecycle 변화 비교
  5. generation 문제인지, retention 문제인지, reload 동작 문제인지 판단

이 순서가 중요한 이유는 두 가지 흔한 실수를 막기 때문입니다.

  • metaspace를 평범한 heap pressure처럼 다루는 실수
  • metadata가 왜 계속 남는지 보기 전에 metaspace limit부터 올리는 실수

증상이 더 넓은 메모리 압박에 가깝다면 Java OutOfMemoryError와 같이 보세요.


limit은 증상을 보이게 할 뿐 원인을 설명하지 않는다

java -XX:MaxMetaspaceSize=256m -jar app.jar

dynamic proxy나 classloader가 계속 새 class를 만들면 metaspace 압박은 flatten되지 않고 계속 늘 수 있습니다.

이 limit은 문제가 언제 눈에 드러나는지에 영향을 줄 수는 있어도, 왜 metadata가 계속 늘었는지를 설명해 주지는 않습니다.


metaspace 장애마다 물어볼 질문

아래를 물어보면 도움이 됩니다.

  • 시간이 갈수록 어떤 class가 추가되는가
  • 그 class는 어떤 classloader가 소유하는가
  • 그 classloader는 언제 unreachable해져야 하는가
  • 실제로 그 release가 일어나고 있는가

이 프레이밍이 좋은 이유는 metaspace 장애가 일반 객체가 아니라 class metadata 차원에서 일어나는 reachability 문제이기 때문입니다.


FAQ

Q. metaspace가 높으면 항상 heap leak인가요?

아닙니다. metaspace 압박은 일반 heap object retention보다 class metadata, generated class, classloader retention 문제인 경우가 많습니다.

Q. 무엇부터 보는 게 가장 빠른가요?

metaspace 압박이 맞는지 먼저 확인하고, 그다음 classloading churn과 classloader lifecycle을 보세요.

Q. MaxMetaspaceSize만 늘리면 되나요?

시간을 벌어줄 수는 있지만, metadata가 healthy한 flattening 없이 계속 늘고 있다면 근본 해결은 아닙니다.


Sources:

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.