최종 프로젝트를 진행하면서 인프라를 담당하게 되었는데 그 중 마주친 OOM 에러.(22.10.13 THU)
끝끝내 원인을 찾지는 못하였지만 어떻게 문제를 분석하고 임시방편이지만 어떻게 처리하였는지 기록해 보고자 한다.
문제 정의 & 사실 수집
최종 프로젝트 런칭 전, 인프라를 구성하고 배포를 한 뒤 테스트를 진행하는데 갑자기 서버가 죽어버렸다.
로그를 확인하니 java.lang.OutOfMemoryError : Java heap space 를 반복적으로 내뱉더니 이내 서버가 뻗어버렸다.
Out Of Memory Error?
주로 가비지 컬렉터가 새로운 객체를 생성할 공간을 더이상 만들어 주지 못하고, 더이상 힙영역의 메모리가 증가될 수 없을때 나타난다.
원인은 다음과 같이 다양하다.
- Exception in thread "main" : java.lang.OutOfMemotyError: java heap sapce
- Exception in thread "main" : java.lang.OutOfMemotyError: Metaspace
- Exception in thread "main" : java.lang.OutOfMemotyError: Requested array size exceeds VM limit
- Exception in thread "main" : java.lang.OutOfMemotyError: request <size> bytes for <reason>. Out of swap space?
- Exception in thread "main" : java.lang.OutOfMemotyError: <reason> <stacktrace> (Native method)
이 중 나는 시스템 로그에 찍힌대로 java.lang.OutOfMemotyError: java heap sapce 에 대해서 먼저 알아보기로 했다.
Java heap space 란?
자바의 JVM 메모리 영역 중 하나이다.
- Heap Area
- JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역
- new 연산자로 생성된 객체와 배열을 저장
- 힙 영역에 생성된 객체와 배열은 스택 영역의 변수나 다른 객체의 필드에서 참조한다.
- 참조하는 변수나 필드가 없다면 의미 없는 객체가 되어 Garbage Collector에 의해 관리된다
- 힙 영역의 사용 기간 및 스레드 공유 범위
- 객체가 더이상 사용되지 않거나 명시적으로 null 선언 시
- 구성 방식이나 GC 방법은 JVM 벤더마다 다를 수 있음.
- 모든 스레드에서 공유
자세한 설명은 더보기
원인 추론
java.lang.OutOfMemotyError: java heap sapce
- 다양한 원인이 존재하기 때문에 해당 메세지만으로 메모리 누수라고 단언하기 어렵다
- 메모리 크기를 너무 적게 잡아 놓거나, 아예 메모리 크기를 지정하지 않은 경우
- 오래된 객체들이 계속 참조되고 있어서 GC가 되지 않는 경우
- finalize 메소드를 과도하게 사용하는 경우
- 스레드의 우선 순위를 너무 높인 경우
- 큰 덩어리의 객체가 여러개 있을 경우
- 원인이 다양한 만큼 해결책도 다양했다. 일단 이러한 문제를 처음 마주쳐본 입장으로써 이렇게 하나씩 살펴 보기보단 여러개의 해결책을 일단 시도해보는 걸로 하였다.
가설 1) Heap space 메모리 용량 부족
- 원인 1 처럼 기본 크기로만 지정이 된 상태여서 제일 쉽게 추론해낼 수 있는 원인 이었다.
가설 2) Swap 메모리 부족
- (현재로써는 차이점을 알지만) 처음 구글링을 해보았을때 swap 메모리 할당으로 해당 문제를 해결했다는 글을 찾아서 , 일단 메모리가 부족하니 도움이 되지않을까? 싶어서 시도해 보았다.
처음에는 이렇게 찾기 어려울줄 모르고 나름의 가설을 세우고 일단 해결해 보고자 하였다.
참고 블로그