Java Virtual Machine-GC 튜닝
지난 장에서 우리는 다양한 Generational Gcs에 대해 배웠습니다. 이 장에서는 GC를 조정하는 방법에 대해 설명합니다.
힙 크기
힙 크기는 Java 애플리케이션의 성능에 중요한 요소입니다. 너무 작 으면 자주 채워 지므로 GC에서 자주 수집해야합니다. 반면에 힙의 크기를 늘리기 만하면 수집 빈도는 줄어들지 만 일시 중지 시간은 늘어납니다.
또한 힙 크기를 늘리면 기본 OS에 심각한 불이익이 있습니다. 페이징을 사용하여 OS는 응용 프로그램이 실제로 사용 가능한 것보다 훨씬 많은 메모리를 볼 수 있도록합니다. OS는 디스크의 일부 스왑 공간을 사용하여 프로그램의 비활성 부분을 복사하여이를 관리합니다. 이러한 부분이 필요할 때 OS는 디스크에서 메모리로 다시 복사합니다.
머신에 8G의 메모리가 있고 JVM이 16G의 가상 메모리를보고 있다고 가정하면 JVM은 실제로 시스템에서 사용 가능한 8G 만 있다는 것을 알지 못할 것입니다. OS에서 16G를 요청하고 해당 메모리를 확보하면 계속 사용합니다. OS는 많은 데이터를 안팎으로 교환해야하며 이는 시스템에 엄청난 성능 저하를 초래합니다.
그런 다음 이러한 가상 메모리의 전체 GC 중에 발생하는 일시 중지가 발생합니다. GC는 수집 및 압축을 위해 전체 힙에서 작동하므로 가상 메모리가 디스크에서 스왑 될 때까지 많은 시간을 기다려야합니다. 동시 수집기의 경우 백그라운드 스레드는 데이터가 스왑 공간에서 메모리로 복사 될 때까지 많은 시간을 기다려야합니다.
따라서 최적의 힙 크기를 결정하는 방법에 대한 질문이 있습니다. 첫 번째 규칙은 실제로 존재하는 것보다 더 많은 메모리를 OS에 요청하지 않는 것입니다. 이것은 빈번한 스와핑에 대한 문제를 완전히 방지합니다. 머신에 여러 JVM이 설치되어 실행중인 경우 이들을 모두 결합한 총 메모리 요청은 시스템에있는 실제 RAM보다 적습니다.
두 개의 플래그를 사용하여 JVM의 메모리 요청 크기를 제어 할 수 있습니다.
-XmsN − 요청 된 초기 메모리를 제어합니다.
-XmxN − 요청할 수있는 최대 메모리를 제어합니다.
이 두 플래그의 기본값은 기본 OS에 따라 다릅니다. 예를 들어, MacOS에서 실행되는 64b JVM의 경우 -XmsN = 64M 및 -XmxN = 최소 1G 또는 총 실제 메모리의 1/4입니다.
JVM은 두 값 사이에서 자동으로 조정할 수 있습니다. 예를 들어 GC가 너무 많이 발생하는 것을 발견하면 -XmxN 미만이고 원하는 성능 목표를 충족하는 한 메모리 크기를 계속 늘립니다.
애플리케이션에 필요한 메모리 양을 정확히 알고있는 경우 -XmsN = -XmxN을 설정할 수 있습니다. 이 경우 JVM은 힙의 "최적"값을 파악할 필요가 없으므로 GC 프로세스가 좀 더 효율적이됩니다.
세대 크기
YG에 할당 할 힙의 양과 OG에 할당 할 힙의 양을 결정할 수 있습니다. 이 두 값은 다음과 같은 방식으로 애플리케이션의 성능에 영향을줍니다.
YG의 크기가 매우 크면 수집 빈도가 줄어 듭니다. 이로 인해 OG로 승격되는 개체 수가 줄어 듭니다. 반면에 OG의 크기를 너무 많이 늘리면 수집하고 압축하는 데 너무 많은 시간이 걸리고 STW 일시 중지가 길어질 수 있습니다. 따라서 사용자는이 두 값 사이의 균형을 찾아야합니다.
다음은 이러한 값을 설정하는 데 사용할 수있는 플래그입니다.
-XX:NewRatio=N: OG에 대한 YG의 비율 (기본값 = 2)
-XX:NewSize=N: YG의 초기 크기
-XX:MaxNewSize=N: YG의 최대 크기
-XmnN: 이 플래그를 사용하여 NewSize 및 MaxNewSize를 동일한 값으로 설정하십시오.
YG의 초기 크기는 주어진 공식에 의해 NewRatio의 값에 의해 결정됩니다.
(total heap size) / (newRatio + 1)
newRatio의 초기 값이 2이므로 위의 공식은 YG의 초기 값이 전체 힙 크기의 1/3이되도록합니다. NewSize 플래그를 사용하여 YG의 크기를 명시 적으로 지정하여이 값을 항상 재정의 할 수 있습니다. 이 플래그에는 기본값이 없으며 명시 적으로 설정하지 않으면 위의 공식을 사용하여 YG의 크기가 계속 계산됩니다.
Permagen 및 Metaspace
permagen과 metaspace는 JVM이 클래스의 메타 데이터를 보관하는 힙 영역입니다. Java 7에서는이 공간을 'permagen'이라고하고 Java 8에서는 'metaspace'라고합니다. 이 정보는 컴파일러와 런타임에서 사용됩니다.
다음 플래그를 사용하여 permagen의 크기를 제어 할 수 있습니다. -XX: PermSize=N 과 -XX:MaxPermSize=N. Metaspace의 크기는 다음을 사용하여 제어 할 수 있습니다.-XX:Metaspace- Size=N 과 -XX:MaxMetaspaceSize=N.
플래그 값이 설정되지 않았을 때 permagen과 metaspace를 관리하는 방법에는 약간의 차이가 있습니다. 기본적으로 둘 다 기본 초기 크기를 갖습니다. 그러나 메타 스페이스는 필요한만큼의 힙을 차지할 수 있지만 permagen은 기본 초기 값만 차지할 수 있습니다. 예를 들어, 64b JVM에는 최대 영구 크기로 82M의 힙 공간이 있습니다.
지정하지 않으면 메타 공간이 무제한의 메모리를 차지할 수 있으므로 메모리 부족 오류가 발생할 수 있습니다. 이러한 영역의 크기가 조정될 때마다 전체 GC가 발생합니다. 따라서 시작하는 동안로드되는 클래스가 많은 경우 메타 스페이스의 크기가 계속 조정되어 매번 전체 GC가 생성 될 수 있습니다. 따라서 초기 메타 공간 크기가 너무 작은 경우 대규모 응용 프로그램을 시작하는 데 많은 시간이 걸립니다. 시작 시간을 줄이므로 초기 크기를 늘리는 것이 좋습니다.
permagen과 metaspace는 클래스 메타 데이터를 보유하지만 영구적이지 않으며 객체의 경우처럼 GC에서 공간을 회수합니다. 일반적으로 서버 응용 프로그램의 경우입니다. 서버에 새 배포를 할 때마다 새 클래스 로더에 공간이 필요하므로 이전 메타 데이터를 정리해야합니다. 이 공간은 GC에 의해 해제됩니다.