VM Heap Size and Garbage Collection(이하 GC)

(https://docs.oracle.com/cd/E15523_01/web.1111/e13814/jvm_tuning.htm#PERFM158)

Java Heap은 객체가 저장되어 있는 곳입니다. 실행중인 프로그램의 포인터에서 더 이상 객체에 도달 할 수 없으면 “Garbage”로 간주되어 수집(정리)이 됩니다. GC를 수행하는 데 걸리는 시간을 실행 시간의 5% 이내로 조정하는 것이 가장 좋습니다.
JVM Heap Size는 VM이 GC 발생 빈도와 소요시간을 결정합니다. GC의 수용 가능한 비율은 응용 프로그램에 따라 다르며 GC의 실제 시간과 빈도를 분석 한 후에 조정해야합니다. 큰 Heap Size를 설정하면 전체 GC가 느려지지만 덜 자주 발생합니다. 메모리 요구에 따라 Heap size를 설정하면 전체 GC 속도는 빨라지지만 더 자주 발생합니다.
Heap Size를 조정하는 목적은 WebLogic Server가 주어진 시간에 처리 할 수있는 클라이언트의 수를 최대화하면서 JVM이 가비지 콜렉션을 수행하는 데 걸리는 시간을 최소화하는 것입니다. 벤치마킹 중 성능을 최대로 유지하려면 높은 Heap Size 값을 설정하여 벤치 마크 전체 실행 중에 가비지 수집이 발생하지 않도록 할 수 있습니다.
Heap Size가 부족한 경우 아래와 같이 Error가 표시 될 수 있습니다.

java.lang.OutOfMemoryError «no stack trace available»
java.lang.OutOfMemoryError «no stack trace available»
Exception in thread “main”

Heap Size 조정 팁

Heap Size의 경우 VM에서 사용하는 최대 메모리 양이 사용 가능한 실제 RAM의 양을 초과하지 않도록 값으로 설정해야 합니다. 이 값을 초과하면 OS가 페이징을 시작하고 성능이 크게 저하되기때문입니다.
운영환경에서는 Max Heap Size와 Min Heap Size를 동일한 값으로 설정하여 Heap Memory를 지속적으로 늘리거나 줄이는 데 사용되는 VM 리소스를 낭비하지 않는게 좋습니다. (GC 모니터링 방법 / d2.naver.com)

Java HotSpot VM Heap Size Option

Task Option Description
Young Gen Heap Size 설정 -XX : NewSize 일반적으로 Heap Size의 4 분의 1로 설정 합니다. 수명이 긴 오브젝트에 대해 이 옵션의 값을 늘리는게 좋습니다.
Young Gen Heap Size 최대 설정 -XX : MaxNewSize Young Gen Heap Size의 의 최대 크기를 설정을 위한 옵션입니다.
Young Gen 내 Survivor 비율 설정 -XX : SurvivorRatio Young Gen 내 Eden / survivor 공간 크기의 비율을 설정하는 옵션입니다. 이 값을 8로 설정 한 다음 가비지 수집을 모니터 후 튜닝하는게 좋습니다.
초기 Heap Size 설정 -Xms 일반적으로 초기갓은 -Xms와 -Xmx 값이 동일합니다.
최대 Heap Size 설정 -Xmx Heap Size의 최대 크기를 설정하는 옵션입니다.
Perm Gen 내 Method Area size -XX:PermGen java 8 에서 제거
Perm Gen 내 최대 Method Area size -XX:MaxPermGen java 8 에서 제거
※ 이 값의 기본 크기는 바이트 단위입니다. 값에 KByte를 나타내는 ‘k’또는 ‘K’를 추가하고 MByte를 나타내는 ‘m’또는 ‘M’, GByte를 나타내는 ‘g’또는 ‘G’를 추가하면 설정이 가능합니다.

참고 : https://slipp.net/wiki/pages/viewpage.action?pageId=26641949
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

Heap Memory의 구성요소 및 관련 Option

(출처 : https://stackoverflow.com/questions/2129044/java-heap-terminology-young-old-and-permanent-generations)

jvm_option_desc

GC 종류 및 방식

(출처 : https://slipp.net/wiki/pages/viewpage.action?pageId=26641949)
  option Young Gen Old Gen GC 방식 장 / 단점
Serial GC -XX:+UseSerialGC generation algorithm mark-compact-algorithm 1) Old Gen 내 객체 식별(mark)
2) Heap 앞부분부터 확인해 살아있는것만 남김(sweep)
3) 각 객체들이 연속되게 쌓이도록 heap 의 가장 앞 부분부터 적재(compact)
적은 메모리와 단일 코어서버운용으론 불가STW 시간 소요
Parallel GC -XX:+UseParallelGC -XX:ParallelGCThreads=value generation algorithm(multiple thread) mark-compact-algorithm - Serial GC 와 동일하나 Young Gen을 병렬처리 serial GC 보단 빠르나많은 메모리와 코어 갯수가 많을 때나 유리STW 시간 소요
Parallel Old GC -XX:+UseParallelOldGC generation algorithm(multiple thread) parallel compactiong algorithm(mark-summary-compaction) - Serial GC 를 기본으로 수행을 하지만 compaction 단계 이전에 summary 라는 단계를 가짐.
- 해당 작업에서는 이전 GC 이후의 메모리를 인덱싱하는 작업을 우선 수행하고해당 인덱스가 마무리된 메모리에 compact 작업을 수행하게 됨.
- 공간에 대한 인덱싱 작업때문에 약간의 메모리를 더 소모할 수 있음.
참고 : https://stackoverflow.com/questions/20430058/parallel-compacting-collector-algorithm
Parallel 의 장점을 가져가고,동시에 old 영역에 대한 GC 처리량도 늘림약간의 메모리 소모가 더 발생할 수 있음
CMS(Concurrent Mark-Sweep) -XX:+UseConcMarkSweepGC -XX:+UseParNewGC-XX:+CMSParallelRemarkEnabled-XX:CMSInitiatingOccupancyFraction=value-XX:+UseCMSInitiatingOccupancyOnly parallel copy algorithm concurrent mark-and-sweep algorithm 1) ROOT set 에 의해 직접 참조되는 객체들을 Marking (initial mark)
2) 애플리케이션 동작 중 작업하며 살아있는 객체 식별 (concurrent mark)
3) 2번에서 새로 추가로 참조가 끊긴 객체를 확인 (remark)
4) 참조가 끊긴 모든 쓰레기 정리 (concurrent sweep)모든 작업은 독립 쓰레드가 병렬로 처리. compact 단계는 기본으로 제공하지 않음.
애플리케이션 응답속도가 매우 빠름. 다른 GC 보다 메모리와 CPU 를 많이 사용, Compact 단계가 없음 (살아있는 객체에 대해 메모리 정리하는 작업)Compact 단계가 존재하지 않아 조각난 메모리가 많음. (메모리의 단편화) 자칫 위의 사유로 무한 Full GC 발생 가능
G1 GC -XX:+UnlockExperimentalVMOptions-XX:+UseG1GC evacution pause concurrent marking - new, old 영역에 연속된 메모리 주소에 대한 구조적 개념을 배재, 메모리 영역을 통으로 관리. 전체 메모리를 Region 이라 부르는 블럭 형식 단위로 분할하고 이 영역에 객체를 할당 XX:G1HeapRegionSize=size로 블럭단위로 설정이 가능.
- JDK6 u26 에서는 init heap size / 2048이 기본 단위. 기존의 메모리 할당(new => old) 을 promotion 이라 칭했는데 이를 G1 에서는 Evacuation 이라 칭함.
내부적으로 GC동작에 대한 기준은 STW 시간에 대한 목표치를 기반함. XX:MAXGCPauseMillis=, 기본값 : 200ms 전체 region 을 대상으로 객체 referrer를 참조하는 card table 소지.(card table 은 old 객체가 현재 참조중인 new 객체에 대한 메모리 주소를 관리, 이를 Remembered Sets 이라함.
- GC 가 시작되면 Young region을 정리(minor gc) 후 evacuation 과 compation (major gc) 가 연속으로 진행됨.
1) G1 으로 설정한 JVM 은 New/s0,1/old 로 구분되는 물리적 메모리 구분없이 region 으로 불리는 메모리블럭을 구성하면서 기동. (논리적으로 구분되어있지만, 물리적 구분 없음)
2) 초기 구동시에 생성되는 객체들은 임의의 region 에 생성되며 해당 객체의 referrer 정보는 remembered set에 저장.
3) Young GC (minor gc) 수행은
a. remembered set referrer 정보를 참조하여 살아있지 않는 것만 마킹하며 싱글스레드로 진행.
b. region 의 살아있는 객체 밀도가 낮은 region 에 대해 evacuation 진행 정리대상에 region 내에 살아있는 객체는 다른 region으로 복사되며 나머지를 폐기.
4) old gc (major gc) 수행은
a. young gc 의 evacuation와 동일하게 진행.
b. 이때 메모리가 부족하거나 GC 수행시간이 설정보다 길어질것으로 판단되면, GC 를 다시 수행하면서 survivor, old 영역으로 지정된 region 들이 메모리 앞쪽으로 정리하는 compation 단계를 거침.
(region 단위로 이동)
- Server style GC 라고 불림.
- 각 Gen 들의 referrer 를 관리하기 위한 overhead 존재로 Xmx 2G 이상의 Heap 메모리를 요구.

참고 : 각 JDK 버전 별 Default GC

버전 GC  
Java 7 Parallel GC  
Java 8 Parallel GC  
Java 9 G1 (proposed)  

참고 사이트