태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

[ Enterprise Java는 거대한 동기화 머신이다 - GC ] Enterprise Java & Oracle 성능 분석의 기초 - Part7

Enterprise Java 2007.09.04 15:32
[Enterprise Java는 거대한 동기화 머신이다]

IBM JVM

- Heap Management & Garbage Collection
IBM JVM의 Heap 메커니즘은 전통적으로 Sun HotSpot JVM과 매우 다른 방식을 사용해왔다. 간단하게 말하면, IBM JVM은 Generation 기법을 사용하지 않았다. 따라서 Young(New)과 Old(Tenured) Generation의 구분이 존재하지 않았다.

"않았다"라는 과거 시제를 사용한 것에 유의하자. IBM Java 5(JDK 1.5)부터는 Generation 알고리즘에 기반한 GC 기법을 제공한다. 이는 Sun HotSpot JVM 계열에서 보편적으로 검증된 방법론을 흡수한 것으로 이해할 수 있다.

Sun HotSpot JVM의 GC 기법을 다룬 블로그(http://blog.naver.com/ukja/120041944714)에서 성능을 보는 두가지 대표적인 관점인 [응답시간(Response Time)]과 [처리량(Throughput)]에 대해 언급한 바 있다. IBM JVM의 GC도 동일한 관점에서 분류된다. JDK 1.4 까지는 다음 세 개의 Garbage Collector가 제공되었다.

  • Throughput 최적화 Collector: -Xgcpolicy:optthruput 옵션으로 지정 (기본값).
  • Response Time 최적화 Collector: -Xgcpolicy:optavgpause 옵션으로 지정
  • SubPool Collector: -Xgcpolicy:subpool 옵션으로 지정. Heap을 여러 개의 Sub pool로 나누어 관리함으로써 성능 향상을 꾀한다. 16개 이상의 멀티 CPU 환경에서만 사용할 것을 권장한다.

JDK 1.5에서는 다음 Garbage Collector가 추가되었다.

  • Generational Concurrent Collector: -Xgcpolicy:gencon 옵션으로 지정. Sun JVM의 Generation 기법과 매우 유사하다.

- Mark and Sweep + Compaction
IBM JVM이 제공하는 기본 Collector는 Young/Old Generation의 구분을 사용하지 않기 때문에 Minor GC(copy), Major GC(mark and sweep)와 같은 구분 또한 존재하지 않는다. 대신 메모리를 정리하는 일련의 과정을 Mark and Sweep + Compaction으로 구분한다. Mark and Sweep 단계는 Sun JVM에서도 이미 언급된 바 있다. 이른바 Stop the World 작업으로 Application Thread를 멈춘 상태에서 Alive Object를 Mark하고(Dead Object를 찾고), 지우는 작업을 한다. IBM JVM은 Mark and Sweep 단계를 매우 "가벼운" 작업으로 간주한다. 비록 이 단계가 Sun JVM의 Major GC와 비슷한 속성을 지니고 있지만 Major GC에 비해서는 단순한 작업으로 구현되어 있다.

Sun JVM의 Major GC와 가장 비슷한 작업은 Compaction 단계에서 발생한다. Mark and Sweep으로 메모리 정리를 한 후에도 오브젝트 할당에 필요한 여유 메모리를 찾지 못하면 Compaction, 즉 압축이 발생한다. Mark and Sweep 작업이 단순히 Dead Object를 정리하는 작업인데 반해 Compaction 작업은 흩어진 프리 메모리를 합치는 작업을 하기 때문에 Mark and Sweep 단계에 비해 많은 시간을 필요로 한다. 다행히 일반적으로 Compaction 작업은 드물게 발생한다.

Mark and Sweep 단계를 거쳤음에도 불구하고 오브젝트 할당에 필요한 메모리를 찾지 못하는 이유는 단편화(Fragmentation)에 있다. IBM JVM의 Mark and Sweep은 Compaction 작업을 하지 않기 때문에 프리 메모리가 여기 저기에 흩어지는 현상이 생기게 된다. 이런 현상을 단편화라고 부른다. 가령 1M의 프리 메모리가 연속되지 않은 10K 청크 100개로 흩어져 있다고 가정해보자. 이 경우 비록 총 1M의 프리 메모리가 존재하지만 20K의 연속된 메모리는 할당될 수없다. 이런 경우에는 Compaction 작업이 추가로 발생하게 된다.

Sun HotSpot JVM에서는 Major GC를 최적화하는 것이 Heap 튜닝의 대표적인 기법이듯이, IBM JVM에서는 Compaction을 줄이는 것이 Heap 튜닝의 대표적인 기법이다.

---(참조)-----------------------------------------------------------------------------------
IBM이 제시하는 Heap 튜닝 기법중 하나가 길이가 긴 Array를 사용하지 말라는 것이다. 이 기법의 근거가 바로 Heap의 단편화에 있다. Application이 일정 시간 동작하고 나면 필연적으로 단편화가 발생한다. 이럴 때 길이가 긴 Array를 사용하면 연속된 메모리 공간을 할당받지 못해 Compaction 작업이 발생하게 된다. 따라서 효과적인 자료 구조를 사용해서 작은 크기의 Array를 여러 개 사용할 것을 권장하고 있다.
---------------------------------------------------------------------------------------------

- Mark and Sweep과 Garbage Collector
Throughput 최적화 Collector는 말 그대로 Mark and Sweep+Compaction 기법을 사용한다. 주기적으로 Mark and Sweep이 발생하고 필요한 경우 Compaction을 통해 메모리 병합을 시도한다.

이러한 일련의 GC 작업은 Application Thread를 완전히 멈춘 상태에서 진행되기 때문에 GC 작업 자체는 가장 최적화된다. 그 만큼 처리량은 높아지지만, Pause Time이 길어지면서 Response Time이 길어지는 단점이 생긴다.

Response Time 최적화 Collector는 Mark and Sweep+Compaction 기법에 약간의 변화를 가한다. Mark and Sweep 단계를 되도록이면 Application Thread를 멈추지 않는 상태에서 Concurrent 하게 진행한다. 즉 Concurrent Mark 단계와 Concurrent Sweep 단계를 추가로 두어서 Mark and Sweep에 의한 Pause Time을 최소화한다. Concurrent Mark와 Concurrent Sweep 단계는 Application Thread와 같이 동작하며, 그 만큼 Applicaiton Thread의 CPU 자원을 소모한다. 따라서 Throughput 최적화 Collector에 비해 Throughput이 다소 떨어질 수 있다.

---(참조)----------------------------------------------------------------------------------
IBM JVM의 Response Time 최적화 Collector의 GC 수행 기법이 Sun JVM의 Low Pause Collector(CMS Collector)와 매우 유사한 것은 우연이 아니다. 두 Vendor가 최신 Garbage Collection 기법을 서로 차용하고 개발하는 과정에서 자연스럽게 발생하는 공명 현상이다
--------------------------------------------------------------------------------------------

- Global GC와 Scavenger GC
IBM JVM에서는 Minor GC와 Major GC라는 분류법은 존재하지 않는다. 대신 Global GC와 Scavenger GC라는 분류법이 존재한다. Throughput 최적화 Collector(optthruput)와 Response Time 최적화 Collector(optavgpause)가 행하는 GC는 무조건 Global GC이다. 즉 Sun JVM의 관점에서 보면 항상 Major GC를 수행하고 있는 셈이다. 하지만 Compaction이 일어날 때만 진정한 의미에서 Major GC와 같다고 할 수 있다.

IBM JDK 1.5에서 추가된 Generational Concurrent Collector(gencon)에서는 Scavenger GC가 Minor GC의 역할을 하고 Global GC가 Major GC의 역할을 한다. Scavenger GC는 Mark and Sweep 방식이 아닌 Copy 방식(Alive Object를 Allocate Space에서 Survivor Space로 복사하는 것을 의미)을 사용하며 Global GC에서 Mark and Sweep+Compaction을 사용한다.

- IBM JVM의 장점
IBM JVM에 제공하는 기본 Collector(optthruput, optavgpause)의 장점은 안정된 GC 패턴이다. Sun JVM이 제공하는 Generation 기법이 훨씬 지능적이고 효과적인 것은 부인할 수 없는 사실이다. 특히 튜닝을 통해 Major GC를 최소화하고 Minor GC를 최적화했다면 GC에 의한 성능 저하 현상을 대부분 피할 수 있다. 하지만 Major GC에 의한 Spike 현상(갑자기 GC Pause Time이 급증하는 현상)은 항상 고질적인 문제로 남아 있다. Minor GC 시에는 안정된 패턴을 보이다가도 Major GC가 발생할 때 수초 ~ 수십초까지 GC Pause가 발생한다면 성능에 미치는 영향은 치명적일 수 있다.

반면 IBM JVM에서는 상대적으로 Compaction의 발생 빈도가 높지 않기 때문에 전반적으로 안정적인 패턴을 보인다. 이 말은 역설적으로 IBM JVM에서 Compaction이 최적화되고, Sun JVM에서 Major GC가 최적화되면 둘 사이에는 큰 성능 차이가 없을 것이라는 것을 암시하기도 한다.

(위의 말이 IBM JVM이 항상 안정적이라는 말은 아니며, Sun JVM에 비해 성능이 뛰어나다는 의미는 더더욱 아니다)

- IBM JVM의 단점
Sun JVM이 New/Old Generation의 크기, Survivor Ratio 등의 조정을 통해 세밀한 튜닝이 가능한 반면, IBM JVM에서 optthruput이나 optavgpause를 사용할 경우에는 튜닝에서의 세밀함이 부족한 편이다.

JDK 1.5에서 제공하는 gencon Collector를 쓸 경우에는 Sun JVM과 거의 비슷한 설정이 가능하다. 하지만 튜닝가능한 옵션 수는 비교적 작은 편이다.

(하지만 역설적으로 튜닝 옵션이 적다는 것은 더 자동화되어 있고 편리하다는 의미이기도 하다)


- IBM JVM의 GC 관련 중요 옵션들

-Xms, -Xmx: Heap의 최소(시작)크기, 최대 크기를 결정한다.

-Xgcpolicy: : optthruput|optavgpause|gencon|subpool. Garbage Collector의 종류(
따라서 Heap 관리의 종류)를 결정한다.

-Xdisableexplicitgc: System.gc()에 의한 GC를 비활성화한다.

-Xgcthreads: Parallel GC 작업을 할 Thread 개수를 지정한다. Default = CPU#-1. 만
일 여러 프로세스가 CPU를 나누어 쓰는 환경이라면 이 값을 낮출 필요가 있다.

-Xloa: LOA(Large Object Area)를 사용할 지의 여부를 결정한다. Default는 활성화상태이다.

-Xloainitial, -Xloamaximum, -Xloaminium: LOA의 초기 크기, 최대크기, 최소 크기를 지정한다. 0 ~ 1 사이의 값을 지정한다.

-Xmaxe, -Xmine: Heap expansion이 증가할 최대/최소 크기를 지정한다.

-Xmaxf, -Xminf: Heap 크기를 조정할 Free Memory의 비율을 결정한다. Default 값은 0.6(60%), 0.3(30%)이다. 즉, Free Memory가 전체 Memory의 60%이상이 되면 Heap Shrinkage가 발생하고, 전체 Memory의 30% 이하이면 Heap Expansion이 발생한다.

-Xmn, -Xmns, -Xmnx: Generational Concrreunt Collector를 사용할 경우 New(Nursery) Generation의 크기(최대/최소를 동일하게), 최소(시작)크기, 최대크기를 지정한다.

-Xmo, -Xmos, -Xmox: Generational Concurrent Collector를 사용할 경우 Old(Tenured) gEneration의 크기(최대/최소를 동일하게), 최소(시작)크기, 최대크기를 지정한다.

-Xpartialcompactgc: Incremental Compaction을 활성화한다. 만일 Compaction에 의한 성능 저하가 발생한다고 판단되면 이 옵션을 사용해본다.

-Xsoftrefthreshold: Soft Reference 객체를 몇 번째 GC Cycle에 해제할지의 여부를 결정한다. Default는 32이다. 즉, 32번째 GC Cycle까지 Soft Reference가 참조하고 있는 객체가 Mark되지 않았다면(즉 Live Object로 판단되지 않았다면) 메모리에서 해제된다. 이 값을 낮춤으로써 프리 메모리가 좀더 빨리 확보되도록 할 수 있다. 하지만 그 만큼 Soft Reference의 효율성은 떨어진다.

---(참조)--------------------------------------------------------------------------------
Reference 객체의 의미는 다음 문서에 잘 설명되어 있다. http://java.sun.com/developer/technicalArticles/ALT/RefObj/

Reference 객체는 Application 개발자가 Garbage Collector의 행동 양식에 영향을 줄 수 있는 유일한 방법이다. 대용량의 메모리를 사용하는 큰 Application 작성자라면 반드시 Reference 객체를 효과적으로 사용할 수 있어야 한다.
------------------------------------------------------------------------------------------
-verbosegc: GC 로그를 남긴다.

-Xverbosegclog: : GC 로그를 특정 파일명으로 남긴다.

간단한 성능 테스트
아래 결과는 세 가지 주요 Collector(optthruput, optavgpause, gencon)의 성능을 비교 테스트한 결과이다.

Case1: Heap Size = 512M, -Xgcpolicy:optthruput
23999893 allocated
Global GC = 22
Scavenger GC = 0
Total GC Time = 7.967951
Avg GC Time = 0.362180

Case2: Heap Size = 512M, -Xgcpolicy:optavgpause
21612553 allocated
Global GC = 23
Scavenger GC = 0
Total GC Time = 0.915822
Avg GC Time = 0.039818

Case3: Heap Size = 512M, -Xgcpolicy:gencon
14321989 allocated
Global GC = 4
Scavenger GC = 122
Total GC Time = 24.730480
Avg GC Time = 0.196274

위의 결과를 해석해보면
  • 처리량은 optthruput 옵션을 사용한 경우에 가장 뛰어나다. 이것은 예상된 결과이다.
  • GC에 의한 Pause Time은 optavgpause인 경우에 가장 낮다. 이것 역시 예상된 결과이다. IBM JVM의 GC가 매우 안정적이고 예상 가능한 방식으로 작동하는 것을 확인할 수 있다.
  • gencon을 사용한 경우 GC Pause Time은 optthruput에 비해 개선되지만 처리량이 지나치게 낮아지는 것을 알 수 있다. 그 이유는 첫째, gencon을 사용할 경우 약간의 옵션 튜닝이 필요할 수 있다는 것과 현재의 Application 패턴이 gencon에는 맞지 않다는 것이다.
J2EE 환경의 복잡한 Application에서는 gencon을 사용한 경우 더 우수한 성능을 나타낸다는 테스트 결과가 있다. 아래 테스트 결과는 복잡한 J2EE Application에서 optthruput과 gencon 옵션을 사용한 경우의 GC 패턴을 보여주고 있다.

파란색 = optthruput, 녹색 = gencon




위의 결과를 보면 처리량면에서도, Pause Time 면에서도 gencon을 사용한 경우가 더 우수한 성능을 보이는 것을 확인할 수 있다.(단 gencon을 사용한 경우 Global GC에 의한 Spike 현상이 나타난 것을 알 수 있다)


아래 결과는 optthruput을 사용하면서 Heap Size를 조정한 경우의 테스트 결과이다.

Case1: Heap Size = 256M, -Xgcpolicy:optthruput
13000597 allocated
Global GC = 32
Scavenger GC = 0
Total GC Time = 15.830381
Avg GC Time = 0.494699

Case2: Heap Size = 1024M, -Xgcpolicy:optthruput
24214091 allocated
Global GC = 23
Scavenger GC = 0
Total GC Time = 9.089497
Avg GC Time = 0.395196

위의 결과를 보면 Heap Size가 큰 경우가 그렇지 않은 경우에 비해 탁월한 성능 개선 효과가 있는 것을 확인할 수 있다. 또한 Sun JVM에서 볼 수 있었던 Heap Size의 크기와 New/Old Generation의 크기에 의한 미묘한 성능 차이 현상이 발생하지 않고 안정적인 패턴을 보이는 것을 알 수 있다. 이러한 안정적인 패턴이 IBM JVM의 가장 큰 장점이다.

---------------------------------------------------------------------------------------------------
다음 글에 계속...

(PS) 애초에 걱정한 것처럼 점점 용두사미로 전락하고 있다... ㅠㅠ







신고
Trackback 0 : Comments 2
  1. moncler 2013.01.04 15:01 Modify/Delete Reply

    관리자의 승인을 기다리고 있는 댓글입니다

  2. moncler españa 2013.01.05 16:32 Modify/Delete Reply

    관리자의 승인을 기다리고 있는 댓글입니다

Write a comment

티스토리 툴바