|
| 1 | +--- |
| 2 | +title: "JVM Tuning" |
| 3 | +date: "2021-05-30" |
| 4 | +tags: ["Java"] |
| 5 | +summary: "Let's learn about JVM Memory, Life Cycle, and Non-Standard Options" |
| 6 | +description: "JVM Memory 영역, Life Cycle, Non-Standard Options 에 대해서 알아보자" |
| 7 | +--- |
| 8 | + |
| 9 | +:::info |
| 10 | +JVM Memory 영역, JVM Life Cycle, OOME(Out Of Memory Error) 가 발생하는 Case |
| 11 | +JVM 메모리 할당과 Java Stack/Heap Space 와 메모리 할당 정리 |
| 12 | +JVM 표준 옵션인 Standard Options와 JVM 버전와 OS 종류에 따라 존재 여부가 결정되는 Non-Standard Options 중, Non-Standard Options 정리 |
| 13 | +::: |
| 14 | + |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +### JVM Memory 영역 |
| 19 | + |
| 20 | +<div style={{ textAlign: 'center' }}> |
| 21 | + <img src="/img/post/java/jvm/jvm-memory.png" alt="jvm-memory" style={{ display: 'inline-block' }} /> |
| 22 | +</div> |
| 23 | + |
| 24 | +1. Heap Memory |
| 25 | +* JVM 이 객체 또는 동적 데이터를 저장하는 곳 / Garbage Collection 이 일어 나는 곳 |
| 26 | +2. Thread Stack |
| 27 | +* Stack Memory 영역이며, 프로세스의 쓰레드 당 하나의 스택 메모리가 있고, 메소드의 결과 / 반환 값을 저장하거나 지역변수를 저장하는 용도 |
| 28 | +3. MetaSpace |
| 29 | +* 클래스 로더에서 클래스 정의를 저장하는데 사용 |
| 30 | +* 이 공간이 계속 커지면 OS는 여기에 저장된 데이터를 가상 메모리로 이동하여애플리케이션 속도를 저하시킬 수 있음 |
| 31 | +4. Code Cache |
| 32 | +* 컴파일러가 데이터를 저장하는 영역 |
| 33 | +5. Sharded Library |
| 34 | +* 애플이케이션에서 사용할 공유 라이브러리가 기계어로 변환된 채 저장된 영역 |
| 35 | + |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +### JVM Life Cycle |
| 40 | + |
| 41 | +<div style={{ textAlign: 'center' }}> |
| 42 | + <img src="/img/post/java/jvm/jvm-life-cycle.png" alt="vm-life-cycle" style={{ display: 'inline-block' }} /> |
| 43 | +</div> |
| 44 | + |
| 45 | +#### Minor Garbage Collection |
| 46 | +* New 영역에서 일어나는 Garbage Collection |
| 47 | +* Eden 영역에 객체가 가득 차게 되면 첫번째 Garbage Collection 발생 |
| 48 | +* Survivor 1 영역에 값 복사 |
| 49 | +* Survivor 2 영역을 제외한 나머지 영역의 객체들 삭제 |
| 50 | +* Eden 영역과 Survivor 1 영역의 메모리가 기준치 이상일 경우, Eden 영역에 생성된 객체와 Survivor 1 영역에 있는 객체 중 참조되고 있는 객체가 있는 검사 |
| 51 | +* 참조되고 있는 객체를 Survivor 2 영역에 복사 |
| 52 | +* Survivor 2 영역을 제외한 영역의 객체들을 삭제 |
| 53 | +* 일정 시간 이상 참조 되고 있는 객체들을 Old 영역으로 이동 |
| 54 | + |
| 55 | +#### Major Garbage Collection |
| 56 | +* Old 영역에 있는 모든 객체들을 검사 |
| 57 | +* 참조되지 않은 객체들을 한번에 삭제 |
| 58 | +* Minor Garbage Collection 에 비해 시간이 오래 걸리고 실행 중 프로세스가 정지 |
| 59 | + |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +### OOME(OutOfMemoryError) 발생하는 Cases |
| 64 | + |
| 65 | +#### 1. 'java.lang.OutOfMemoryError': Java heap space |
| 66 | +* Java Heap 공간에 새로운 개체를 생성할 수 없을 때 발생 |
| 67 | +* 지정한 Heap 크키가 Application 에 충분하지 않은 경우 발생 |
| 68 | +→ Heap Size 조정 |
| 69 | + |
| 70 | + |
| 71 | +#### 2. 'java.lang.OutOfMemoryError': Metaspace |
| 72 | +* Java class metadata 는 원시 메모리에 할당되는데, class metadata 가 할당될 메타공간이 모두 소모 되면 발생 |
| 73 | +→ MaxMetaSpaceSize 값을 늘려 설정, Heap Size를 줄이면 더 많은 공간을 확보 할 수 있음(Heap과 동일한 주소 공간에 할당 됨) |
| 74 | + |
| 75 | +#### 3. 'java.lang.OutOfMemoryError': requested size bytes for reason. Out of swap space? |
| 76 | +* JVM은 Heap 외에도 자체 구동을 위해 native heap 사용하는데, native heap 이 부족할 때 발생(Heap Size 가 너무 클 경우) |
| 77 | +* heap 영역과 perm 영역을 과하게 설정한 경우, native, stack 영역이 적은 공간으로 설정되어 두 영역의 공간 부족이 나는 경우 |
| 78 | +→ 메모리가 부족해서 swap 을 쓰는 경우 성능이 급격히 저하되므로, 원인을 찾아 제거 |
| 79 | + |
| 80 | +#### 4. 'java.lang.OutOfMemoryError': GC Overhead limit exceeded |
| 81 | +* Garbage Collector 실행과정에서 Java 프로그램이 느려지는 경우 발생 |
| 82 | +* Garbage 수집 후 Java Process 가 Java Collection 을 수행하는데 걸리는 시간의 약 98% 이상 소비하고 Heap 의 2% 미만이 복구 된 상태에서 |
| 83 | +지금까지 수행하는 과정에서 Garbage Collection 중 java.lang.OutOfMemoryError 가 5번 이상 생성되는 경우 발생 |
| 84 | +* 데이터를 할당하는데 필요한 공간이 Heap 에 없는 경우 발생 |
| 85 | +→ Heap Size를 늘린다. |
| 86 | + |
| 87 | +:::warning |
| 88 | +참고) -XX:-UseGCOverheadLimit 로 초과 오버헤드 GC 제한 명령을 해제할 수 있음 |
| 89 | +::: |
| 90 | + |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +### Non-Standard Options (일부) |
| 95 | + |
| 96 | +| Section | Option | Description | |
| 97 | +|--|--|--| |
| 98 | +| Extra Options | Xss | 쓰레드 스택 크기(바이트)를 설정. 기본 값은 플랫폼에 따라 다름, (각 Thread에 할당되는 Stack Size 설정) <br/> Default: Linux/x64(64bit): 1024KB / macOS(64bit): 1024KB / Oracle Solaris/x64(64bit): 1024KB, / Windows: 기본 값은 가상 메모리에 따라 다름| |
| 99 | +| | Xms(-XX:InitialHeap Size) | 초기 Heap Size 설정 <br/> Default: JVM을 server class로 실행시 초기 heap size는 메모리의 1/64 | |
| 100 | +| | Xmx(-XX:MaxHeapSize) | 최대 Heap Size 설정 <br/> Default: JVM을 server class로 실행시 최대 heap size는 메모리의 1/4 | |
| 101 | +| Advanced Runtime Options | XX:MaxDirectMemorySize | java.nio 패키지의 최대 총 크기(바이트)를 직접 버퍼 할당으로 설정. <br/> JVM이 NIO Direct-buffer 할당의 크기를 자동적으로 선택함을 의미 <br/> (default:0)| |
| 102 | +| | XX:ActiveProcessorCount | Garbage Collection 과 ForkJoinPool 과 같은 다양한 작업에 사용할 쓰레드 풀의 크기를 계산하는데 VM이 사용할 CPU 수를 재정의 <br/> 이 플래그는 도커 컨테이너에서 여러 Java 프로세스를 실행할 때 CPU 리소스를 분할 하는데 유용| |
| 103 | +| Advanced Garbage Collection Options | XX:MaxMetaspaceSize | 클래스 메타데이터에 할당할 수 있는 최대 기본 메모리 양을 설정. <br/> 기본적으로 크기 제한 X, 응용 프로그램의 메타데이터 크기는 응용 프로그램 자체, 실행 중인 다른 응용 프로그램 및 시스템에서 사용할 수 있는 메모리 양에 따라서 달라짐.| |
| 104 | +| Advanced JIT Compiler Options | XX:ReservedCodeCacheSize | JIT 컴파일 코드에 대한 최대 코드 캐시 크기를 설정 <br/> (default:240MB) | |
| 105 | + |
| 106 | +--- |
| 107 | + |
| 108 | +### ALL |
| 109 | +:::note |
| 110 | +전체의 Options 은 [공식페이지](https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE)에서 확인 |
| 111 | +::: |
| 112 | + |
| 113 | +큰 틀에서의 Options 구분은 아래와 같다. |
| 114 | + |
| 115 | +| Section | Description | |
| 116 | +|--|--| |
| 117 | +| Extra Options | Java HotSpot Virtual Machine에만 해당 되는 범용 옵션 | |
| 118 | +| Advanced Runtime Options | Java HotSpot VM의 런타임 동작을 제어 | |
| 119 | +| Advanced JIT Compiler Options | Java HotSpot VM에서 수행하는 동적 JIT(Just-In-Time) 컴파일을 제어 | |
| 120 | +| Advanced Serviceability Options | Java용 고급 서비스 가능성 옵션 | |
| 121 | +| Advanced Garbage Collection Options | Garbage collection이 Java HotSpot VM에 의해 수행되는 방법 제어 | |
| 122 | + |
| 123 | +---- |
| 124 | + |
| 125 | +### 💡 **Tips** |
| 126 | + |
| 127 | +#### Xmx, XmX 동일하게 세팅 |
| 128 | +* init과 max 사이에서 Used 메모리가 committed까지 사용하게 되면, 신규 메모리 공간을 요구하는데 약 1초 가량 JVM 메모리 할당 중 멈춰버리는 경우가 발생할 수 있음 |
| 129 | +(init < used < committed < max) |
| 130 | + |
| 131 | +:::neutral |
| 132 | +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. |
| 133 | +::: |
| 134 | + |
| 135 | +#### 개별 Thread 의 Stack Size(-Xss) |
| 136 | +* Thread 별 Stack Size 를 과도하게 줄였을 경우 Stack Overflow Error 발생할 수 있음 |
| 137 | +* 많은 수의 Thread 를 사용하는 Application 의 경우 Thread Stack 에 의한 메모리 요구량이 높아지며 이로 인해서 Out Of Memory Error 발생할 수 있음 |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +:::success |
| 142 | +<b>Think..</b> |
| 143 | +✔ 대부분의 블로그나 참고 자료들은 JDK 8 이하의 버전에 대해서 설명한 것들이 많으므로 걸러서 봐야한다. |
| 144 | +✔ 대표적으로 JDK7 에서는 Heap Memory 영역에 Permanent Generation 영역이 있었지만, JDK8 부터 Native Memory 영역에 MetaSpace 가 생김. |
| 145 | +::: |
0 commit comments