JVM Memory 영역
, JVM Life Cycle
, OOME(Out Of Memory Error) 가 발생하는 Case
/ JVM 메모리 할당과 Java Stack/Heap Space 와 메모리 할당 정리
JVM 표준 옵션인 Standard Options 와 JVM 버전와 OS 종류에 따라 존재 여부가 결정되는 Non-Standard Options 중, Non-Standard Options
에 대해서 정리
JVM Memory 영역
- Heap Memory
JVM 이 객체 또는 동적 데이터를 저장하는 곳 / Garbage Collection 이 일어 나는 곳 - Thread Stack
Stack Memory 영역이며, 프로세스의 쓰레드 당 하나의 스택 메모리가 있고, 메소드의 결과 / 반환 값을 저장하거나 지역변수를 저장하는 용도 - MetaSpace
클래스 로더에서 클래스 정의를 저장하는데 사용 / 이 공간이 계속 커지면 OS는 여기에 저장된 데이터를 가상 메모리로 이동하여 애플리케이션 속도를 저하시킬 수 있음 - Code Cache
컴파일러가 데이터를 저장하는 영역 - Sharded Library 애플이케이션에서 사용할 공유 라이브러리가 기계어로 변환된 채 저장된 영역
JVM Life Cycle
Minor Garbage Collection
- New 영역에서 일어나는 Garbage Collection
- Eden 영역에 객체가 가득 차게 되면 첫번째 Garbage Collection 발생
- Survivor 1 영역에 값 복사
- Survivor 2 영역을 제외한 나머지 영역의 객체들 삭제
- Eden 영역과 Survivor 1 영역의 메모리가 기준치 이상일 경우, Eden 영역에 생성된 객체와 Survivor 1 영역에 있는 객체 중 참조되고 있는 객체가 있는 검사
- 참조되고 있는 객체를 Survivor 2 영역에 복사
- Survivor 2 영역을 제외한 영역의 객체들을 삭제
- 일정 시간 이상 참조 되고 있는 객체들을 Old 영역으로 이동
Major Garbage Collection
- Old 영역에 있는 모든 객체들을 검사
- 참조되지 않은 객체들을 한번에 삭제
Minor Garbage Collection 에 비해 시간이 오래 걸리고 실행 중 프로세스가 정지
OOME(OutOfMemoryError) 발생하는 Cases
1. ‘java.lang.OutOfMemoryError’: Java heap space
- Java Heap 공간에 새로운 개체를 생성할 수 없을 때 발생
- 지정한 Heap 크키가 Application 에 충분하지 않은 경우 발생
→ Heap Size 조정
2. ‘java.lang.OutOfMemoryError’: Metaspace
- Java class metadata 는 원시 메모리에 할당되는데, class metadata 가 할당될 메타공간이 모두 소모 되면 발생
→ MaxMetaSpaceSize 값을 늘려 설정, Heap Size를 줄이면 더 많은 공간을 확보 할 수 있음(Heap과 동일한 주소 공간에 할당 됨)
3. ‘java.lang.OutOfMemoryError’: requested bytes for . Out of swap space?
- JVM은 Heap 외에도 자체 구동을 위해 native heap 사용하는데, native heap 이 부족할 때 발생(Heap Size 가 너무 클 경우)
- heap 영역과 perm 영역을 과하게 설정한 경우, native, stack 영역이 적은 공간으로 설정되어 두 영역의 공간 부족이 나는 경우
→ 메모리가 부족해서 swap 을 쓰는 경우 성능이 급격히 저하되므로, 원인을 찾아 제거
4. ‘java.lang.OutOfMemoryError’: GC Overhead limit exceeded
- Garbage Collectior 실행과정에서 Java 프로그램이 느려지는 경우 발생
- Garbage 수집 후 Java Process가 Java Collection 을 수행하는데 걸리는 시간의 약 98% 이상 소비하고 Heap의 2% 미만이 복구 된 상태에서 지금까지 수행하는 과정에서 Garbage Collection 중 java.lang.OutOfMemoryError가 5번 이상 생성되는 경우 발생
- 데이터를 할당하는데 필요한 공간이 Heap에 없는 경우 발생
→ Heap Size를 늘린다.
참고) -XX:-UseGCOverheadLimit 로 초과 오버헤드 GC 제한 명령을 해제할 수 있음
Non-Standard Options (일부)
Section | Option | Description |
---|---|---|
Extra Options | Xss | 쓰레드 스택 크기(바이트)를 설정. 기본 값은 플랫폼에 따라 다름, (각 Thread에 할당되는 Stack Size 설정) Default: Linux/x64(64bit): 1024KB / macOS(64bit): 1024KB / Oracle Solaris/x64(64bit): 1024KB, / Windows: 기본 값은 가상 메모리에 따라 다름 |
Xms(-XX:InitialHeap Size) | 초기 Heap Size 설정 Default: JVM을 server class로 실행시 초기 heap size는 메모리의 1/64 |
|
Xmx(-XX:MaxHeapSize) | 최대 Heap Size 설정 Default: JVM을 server class로 실행시 최대 heap size는 메모리의 1/4 |
|
Advanced Runtime Options | XX:MaxDirectMemorySize | java.nio 패키지의 최대 총 크기(바이트)를 직접 버퍼 할당으로 설정. JVM이 NIO Direct-buffer 할당의 크기를 자동적으로 선택함을 의미 (default:0) |
XX:ActiveProcessorCount | Garbage Collection 과 ForkJoinPool 과 같은 다양한 작업에 사용할 쓰레드 풀의 크기를 계산하는데 VM이 사용할 CPU 수를 재정의 이 플래그는 도커 컨테이너에서 여러 Java 프로세스를 실행할 때 CPU 리소스를 분할 하는데 유용 |
|
Advanced Garbage Collection Options | XX:MaxMetaspaceSize | 클래스 메타데이터에 할당할 수 있는 최대 기본 메모리 양을 설정. 기본적으로 크기 제한 X, 응용 프로그램의 메타데이터 크기는 응용 프로그램 자체, 실행 중인 다른 응용 프로그램 및 시스템에서 사용할 수 있는 메모리 양에 따라서 달라짐. |
Advanced JIT Compiler Options | XX:ReservedCodeCacheSize | JIT 컴파일 코드에 대한 최대 코드 캐시 크기를 설정 (default:240MB) |
ALL
전체의 Options 은 공식페이지에서 확인
큰 틀에서의 Options 구분은 아래와 같다.
Section | Description |
---|---|
Extra Options | Java HotSpot Virtual Machine에만 해당 되는 범용 옵션 |
Advanced Runtime Options | Java HotSpot VM의 런타임 동작을 제어 |
Advanced JIT Compiler Options | Java HotSpot VM에서 수행하는 동적 JIT(Just-In-Time) 컴파일을 제어 |
Advanced Serviceability Options | Java용 고급 서비스 가능성 옵션 |
Advanced Garbage Collection Options | Garbage collection이 Java HotSpot VM에 의해 수행되는 방법 제어 |
Tips
Xmx, XmX 동일하게 세팅
- init과 max 사이에서 Used 메모리가 committed까지 사용하게 되면, 신규 메모리 공간을 요구하는데 약 1초 가량 JVM 메모리 할당 중 멈춰버리는 경우가 발생할 수 있음 (init < used < committed < max)
Setting -Xms and -Xmx to the same value increases predictability by removing the most important sizing decision from the virtual machine. However, the virtual machine is then unable to compensate if you make a poor choice.
개별 Thread의 Stack Size(-Xss)
- Thread별 Stack Size를 과도하게 줄였을 경우 Stack Overflow Error 발생할 수 있음
- 많은 수의 Thread를 사용하는 Application 의 경우 Thread Stack에 의한 메모리 요구량이 높아지며 이로 인해서 Out Of Memory Error 발생할 수 있음
대부분의 블로그나 참고 자료들은 JDK 8 이하의 버전에 대해서 설명한 것들이 많으므로 걸러서 봐야한다. 대표적으로 JDK7 에서는 Heap Memory 영역에 Permanent Generation 영역이 있었지만, JDK8 에서는 Native Memory 영역에 MetaSpace 가 생김.