본문 바로가기

성능테스트/Heap

[ Heap ] Heap memory 개요

반응형

#1 Java의 메모리 개요

OOME 케이스를 알아보기에 앞서 에러 메시지가 어떤 메모리 영역을 지칭하는 건지, 해당영역이 어떤 JVM Option에 의해 제어를 받는지 알 필요가 있다.

그림1 : Java의 메모리 구조
(출처 : https://help.sap.com)

위 그림에서 제일 위에 있는 Heap과 Metaspace가 우리가 주로 관심있는 공간이다. 이 중에서 Metaspace가 Native Area(=Native Memory, Off-Heap, Non-heap, Direct Memory 등)인 것에 주목하자. Java 8부터 기존의 Permgen 메모리가 Metaspace로 바뀌면서 Native Memory에 할당되게 되었다. Native Memory는 Heap 영역의 바깥인 Off-Heap 공간을 의미하는 것으로 쉽게 시스템의 기본 메모리라고 생각하면 된다. Java 어플리케이션은 크게 위의 Heap과 Off-Heap 두 공간을 활용하여 동작하는데, 따라서 어플리케이션을 배포할 때 메모리 몇 GB를 할당해야 하는지 결정하기 위해서는 단순히 Xmx(Heap 메모리 최대치를 결정하는 Java 옵션) 값만 생각하면 OOME에 빠지기 쉽다. 실제로는 Xmx에 MaxMetaspace값을 더하고, 추가로 프로그램에서 NIO를 사용해 Native Memory를 직접 할당받는 로직을 고려해서 Heap + Native Memory 사용총량으로 할당을 해야 비교적 정확하다. 특히 컨테이너의 경우 계산을 좀 더 정확하게 해야 시스템에서 OOM killed되는 상황을 면할 수 있다. 추가로 Thread 수와 스택사이즈 등 고려할 사항이 조금 더 있지만 이 정도만 해도 기본적으로는 충분하니 여기선 논외로 해도 무방할 듯 하다. 특히, 최근에는 이 Off-Heap을 이용해 성능 향상을 하고 있는 어플리케이션들이 많아서 더 관심을 기울여야 한다. Netty, Spark, Cassandra, Ignite 등 이름만 들으면 알만한 여러 어플리케이션들과 이를 사용하는 파생된 수많은 프로젝트가 여기에 포함된다.

 

 

www.samsungsds.com/kr/insights/1232761_4627.html

 

[Java Memory Profiling에 대하여] 1. JVM 메모리의 이해와 케이스 스터디

[Java Memory Profiling에 대하여] 1. JVM 메모리의 이해와 케이스 스터디

www.samsungsds.com

 

 

#2 OOME 종류

honeymon.io/tech/2019/05/30/java-memory-leak-analysis.html

 

[java] 자바 메모리누수(with 힙덤프) 분석하기 - I'm honeymon(JiHeon Kim).

아직까지는 메모리 릭 등의 문제로 힙덤프(HeapDump)를 생성하고 이를 분석하는 일을 해본 경험은 없다(…​ 이 넓고 얕은 지식이여). 우아한형제들 회사 블로그(도움이 될수도 있는 JVM memory leak 이

honeymon.io

OutOfMemoryError 예외 종류 및 원인

OutOfMemoryError를 진단하기 위해 가장 우선되는 것은 예외의 원인을 판별하는 것이다. 원인을 찾을 수 있도록 예외 출력 텍스트에는 ekdmarhk rkxdms 세부 메시지가 포함된다.

   

java.lang.OutOfMemoryError: Java heap space(Java 힙 공간)

  • 원인: 자바 힙 공간에 새로운 개체를 생성할 수 없는 경우 발생한다. 이 오류가 반드시 메모리 누수를 의미하는 것은 아니다. 지정한 힙 크기(혹은 기본 크기)가 애플리케이션에 충분하지 않은 경우 발생한다. 다른 경우, 생명주기가 긴 애플리케이션의 경우
  • 혹은 finalize를 과도하게 사용하는 애플리케이션에서 발생하기도 한다. 클래스에 finalize 메서드가 있는 경우 해당 개체에 대한 가비지컬렉션 시간에 공간을 확보하지 못한다. finalizer가 finalizer 큐에 담긴 finalizer 큐를 처리하는 속도보다 빠른 속도로 쌓이면서 힙 공간이 가득차면서 발생할 수 있다.
  • 조치: finalization 보류 상태의 객체를 모니터링하는 방법을 고려한다.
    • JConsole 관리도구에서 finalization 상태의 객체 숫자를 확인할 수 있다. 이 도구의 Summary 탭에서 메모리 분석 부분에서 확인할 수 있다. 개수는 대략적일 수 있지만 애플리케이션에 어떤 영향을 끼치는지 확인하고 설정을 변경할 수 있다.
    •  오라클 솔라리스와 리눅스 운영체제에서는 jmap -finalizerinfo 명령어를 통해 대기상태의 finalizer 정보를 확인할 수 있다.
    • java.lang.management.MemoryMXBean#getObjectPendingFinalizationCount() 메서르를 이용해서 대략적인 숫자를 확인할 수 있다.

ava.lang.OutOfMemoryError: GC Overhead limit exceeded(GC 오버해드 한도 초과)

  • 원인: 가비지 컬렉터 실행과정에서 자바 프로그램이 느려지는 경우 발생한다. 가바지 수집 후, 자바 프로세스가 자바 컬렉션을 수행하는데 걸리는 시간의 약 98% 이상을 소비하고 힙의 2% 미만이 복구된 상태에서 지금까지 수행하는 과정에서 가비지 컬렉션 중 java.lang.OutOfMemoryError가 5번 이상 생성되는 경우 발생한다. 이 예외는 일반적으로 데이터를 할당하는 데 필요한 공간이 힙에 없는 경우 발생한다.
  • 조치
    • 힙 크기를 늘린다.
    • -XX:-UseGCOverheadLimit 선택사항을 추가하여 java.lang.OutOfMemoryError 가 발생하는 초과 오버헤드 GC 제한 명령 해제할 수 있다.

java.lang.OutOfMemoryError: Requested array size exceeds VM limit(요청 배열 크기가 VM 제한을 초과합니다.)

  • 원인: 애플리케이션(혹은 애플리케이션이 사용하는 API)이 힙 공간보다 큰 배열을 할당을 시도하는 경우 발생한다. 예를 들어, 애플리케이션이 512MB 크기의 배열을 할당하려하지만 힙의 최대크기가 256MB인 경우 요청배열크기가 VM 제한을 초과하면서 java.lang.OutOfMemoryError를 던진다.
    • 힙 공간 사이즈가 너무 작은 경우
    • 배열 요소를 계산하고 더하는 등 배열을 키우는 경우

java.lang.OutOfMemoryError: Metaspace

  • 원인: 자바 클래스 메타데이터(자바 클래스에 대한 VM 내부표현)는 원시 메모리(== 메타공간)에 할당된다. 클래스 메타데이터가 할당될 메타공간이 모두 소모되면() java.lang.OutOfMemoryError: Metaspace가 발생한다. 클래스 메타데이터가 할당될 공간은 MaxMetaSpaceSize 매개변수로 제한된다.
  • 조치: MaxMetaSpaceSize 값을 늘려 설정한다. MaxMetaSpaceSize는 자바 힙과 동일한 주소 공간에 할당된다. 자바 힙의 크기를 줄이면 더 많은 공간을 확보할 수 있다. 자바 힙 공간에 여유가 있는 경우에 고려해볼 수 있다.

java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?

  • 원인: 자바 HotSpot VM 코드가 네이티브 힙이 고갈되어 네이티브 힙에 할당할 수 없는 경우 발생한다. 이 메시지는 실패한 요청의 (바이트) 크기와 메모리 요청의 이유를 나타낸다. 대개의 경우 할당에 실패한 소스 모듈의 이름을 출력한다.
  • 조치: 네이티브 힙 고갈의 경우는 힙 메모리 로그 및 메모리 맵 정보를 분석하는 것이 유용하다. 이런 유형은 운영체제의 문제 해결 유틸리티를 사용하여 문제를 진단할 수 있다.

java.lang.OutOfMemoryError: Compressed class space(압축된 클래스 공간)

    • 원인: 64비트 플랫폼에서 클래스 메타데이터 포인터는 32비트 오프셋(UseCompressedOops)으로 표현된다. 이 방식은 UseCompressedClassPointers(기본값 활성화,on)으로 제어할 수 있으며 활성화되면 클래스 메타데이터가 사용할 수 있는 공간의 크기가 고정된다. UseCompressedClassPointers에 필요한 CompressedClassSpaceSize를 초과하면 java.lang.OutOfMemoryError: Compressed class space를 던진다.
    • 조치: CompressedClassSpaceSize 크기를 키우거나 UseCompressedClassPointers를 비활성화 시킨다.
    • Note
    • CompressedClassSpaceSize는 허용범위가 있어서 -XX:CompressedClassSpaceSize=4g로 설정할 경우 다음과 같은 메시지를 볼 것이다.
   
  •  

java.lang.OutOfMemoryError: reason stack_trace_with_native_method

  • 원인: 이 메시지가 출력되는 것은 원시 메서드에서부터 스택 드레이스가 출력되었다는 것을 의미하며, 네이티브 메서드에 할당 오류가 발생했음을 의미한다. 이 메시지가 이전 메시지들과 다른 점은 JVM 코드가 아니라 Java Native Interface(JNI) 또는 원시메서드에서 할당실패가 감지되었다는 것이다.
  • 조치: 이 예외가 발생했다면 운영체제가 제공하는 유틸리티를 이용해서 문제점을 진단해야 한다.

Note

발번역이 끝났다!!

자바 애플리케이션에서 메모리 누수가 생기는 경우는 종종 발생한다. 이를 해결하기 위해서 메시지를 잘 살펴보고 생성된 힙덤프 파일 및 로그 파일을 살펴보면서 원인을 분석하여 문제를 찾아내는 것이 중요하다.

반응형

'성능테스트 > Heap' 카테고리의 다른 글

[ Heap ] Full GC 발생시키기  (0) 2022.12.22