< 조병욱 > 1. GC란무엇인가? GC는 Garbage Collection의약자로 Java 언어의중요한특징중의하나이다. GC는 Java Application에서사용하지않는메모리를자동으로수거하는기능을말한다. 예전의전통적인언어인 C에서는 malloc, free 등을이용해서메모리를할당하고, 일일이그메모리를수거해줘야했다. 그러나 Java 언어에서는 GC 기술을사용함에따라, 개발자는메모리관리로부터좀더자유롭게되었다. < 그림 2. Java 메모리구조 > Java의메모리영역은앞에서이야기한두영역 (Young 영역, Old 영역 ) 과 Perm 영역이렇게 3가지로영역으로구성된다. 2. GC의동작방법은어떻게되는가? 1) JVM 메모리영역 GC의동작방법을이해하기위해서는 Java의메모리구조를먼저이해할필요가있다. 일반적으로 Application에서사용되는객체는오래유지되는객체보다, 생성되고얼마안있어서사용되지않는경우가많다. < 그림 1 참조 > 영역 New/Young Old 영역 Perm 영역 < 표 1. Java 메모리영역 > 설명 이영역은 Java 객체가생성되자마자저장되고, 생긴지얼마안되는객체가저장되는곳이다. Java 객체가생성되면이영역에서저장되다가, 시간이지남에따라우선순위가낮아지면 Old 영역으로옮겨진다. New/Young 영역에서저장되었던객체중에오래된객체가이동되어서저장되는영역 Class,Method 등의 Code 등이저장되는영역으로 JVM 에의해서사용된다. 2) GC 알고리즘 < 그림 1. 메모리 foot print> 그러면이메모리영역을 JVM 이어떻게관리하는지에대해서알아보자. JVM 은 New/Young 영역과, Old 영역이두영역에대해서만 GC 를수행한다. Perm 영역은앞에서설명했듯이 Code가저장되는영역이기때문에, GC 가일어날필요가없다. Perm 영역은 Code 가모두 Load되고나면거의일정한수치를유지한다. 그래서 Java에서는크게두가지영역으로메모리를나누는데 Young 영역과 Old 영역이그것이다. Young 영역은생긴지얼마안된객체들을저장하는장소이고, Old 영역은생성된지오래된객체를저장하는장소이다. 각영역의성격이다른만큼 GC의방법도다르다. 먼저 Java의메모리구조를살펴보자. Minor GC 먼저 New/Young 영역의 GC방법을살펴보자. New/Young 영역의 GC를 Minor GC 라고부르는데, New/Young 영역은 Eden과 Survivor라는두가지영역으로또나뉘어진다. Eden 영역은 Java 객체가생성되자마자저장되는곳이다. 이렇게생성된객체는 Minor GC 가발생할때 Survivor 영역으로이동된다. 10 www.bea.co.kr
Bea Enterprise Solution Technical News Survivor 영역은 Survivor 1과 Suvivor 2 영역두영역으로나뉘어지는데, Minor GC가발생하면 Eden과 Survivor 1에 Alive되어있는객체를 Suvivor 2로복사한다. 그리고 Alive 되어있지않는객체는자연히 Suvivor 1에남아있게되고, Survivor 1과 Eden 영역을 Clear한다. ( 결과적으로 Alive된객체만 Survivor 2로이동한것이다.) 다음번 Minor GC 가발생하면같은원리로 Eden과 Survivor 2 영역에서 Alive되어있는객체를 Survivor 1에복사한다. 계속이런방법을반복적으로수행하면서 Minor GC를수행한다. Eden 영역에 Alive된객체와 Suvivor 1 영역에 Alive된객체를 Survivor 2에 copy한다 Eden 영역과 Suvivor 2 영역을 clear한다. 이렇게 Minor GC 를수행하다가, Survivor 영역에서오래된객체는 Old 영역으로옮기게된다. 이런방식의 GC 알고리즘을 Copy & Scavenge라고한다. 이방법은매우속도가빠르며작은크기의메모리를 Collecting 하는데매우효과적이다. Minor GC의경우에는자주일어나기때문에, GC에소요되는시간이짧은알고리즘이적합하다. < 그림 3-3. 3 rd Minor GC> 객체가생성된시간이오래지나면 Eden과 Suvivor 영역에있는오래된객체들을 Old 영역으로이동한다. 이내용을그림을보면서살펴보도록하자. Full GC Old 영역의 Garbage Collection을 Full GC라고부르며, Full GC에서는 Mark & Compact라는알고리즘을이용한다. Mark & Compact 알고리즘은전체객체들의 reference를쭉따라가면서 reference가연결되지않는객체는 Mark 한다. 이작업이끝나면사용되지않는객체는모두 Mark가되고, 이 mark된객체를삭제한다.< 그림 4 참고 > ( 실제로는 compact라고해서, mark된객체로생기는공간을 unmark된즉사용하는객체로메꾸어버린다.) < 그림 3-1. 1 st Minor GC> Eden에서 Alive된객체를 Suvivor1으로이동한다. Eden 영역을 Clear한다. Full GC는매우속도가느리며, Full GC가일어나는도중에는순간적으로 Java Application이멈춰버리기때문에, Full GC가일어나는정도와 Full GC 에소요되는시간은 Application의성능과안정성에아주큰영향을준다. < 그림 3-2. 2 nd Minor GC> < 그림 4. Full GC> www.bea.co.kr 11
3. GC 가왜중요한가? 2) Parallel GC Garbage Collection 중에서 Minor GC 의경우보통 0.5 초이내에끝나기때문에큰문제가되지않는다. 그러나 Full GC 의경우보통수초가소요가되고, Full GC동안에는 Java Application이멈춰버리기때문에문제가될수있다. 예를들어게임서버와같은 Real Time Server를구현을했을때, Full GC 가일어나서 5초동안시스템이멈춘다고생각해보자. 또일반 WAS 에서도 5~10초동안멈추면, 멈추는동안사용자의 Request가 Queue에저장되었고, Full GC가끝난후에그요청이한꺼번에들어오게되면과부하에의한여러장애를만들수있다. 그래서원활한서비스를위해서는 GC를어떻게일어나게하느냐가시스템의안정성과성능에큰변수로작용할수있다. JDK 1.3까지 GC는하나의 Thread에서이루어진다. Java가 Multi Thread환경을지원함에도불구하고, 1 CPU 에서는동시에하나의 Thread만을수행할수밖에없기때문에, 예전에는하나의 CPU 에서만 GC를수행했지만, 근래에들어서하나의 CPU 에서동시에여러개의 Thread를실행할수있는 Hyper Threading기술이나, 여러개의 CPU 를동시에장착한 HW 의보급으로하나의 HW Box 에서동시에여러개의 Thread를수행할수있게되었다. JDK 1.4부터지원되는 Parallel GC는 Minor GC 를동시에여러개의 Thread를이용해서수행하는방법으로하나의 Thread를이용하는것보다훨씬빨리작업할수있다. 4. 다양한 GC 알고리즘 앞에서설명한기본적인 GC방법 (Scavenge와 Mark and compact) 이외에 JVM에서는좀더다양한 GC 방법을제공하고그동작방법이나사용방법도틀리다. 이번에는다양한 GC 알고리즘에대해서알아보자. 현재 (JDK 1.4) 까지나와있는 JVM의 GC방법은크게아래 4가지를지원하고있다. - Default Collector - Parallel GC for young generation (from JDK 1.4 ) - Concurrent GC for old generation (from JDK 1.4) - Incremental GC (Train GC) 1) Default Collector < 그림 5. Parallel GC 개념도 > < 그림 5> 을보자왼쪽의 Default GC 방법은 GC가일어날때 Thread들이작업을멈추고, GC를수행하는 thread 만 gc를수행한다 ( 그림에서빨간영역 ), Parallel GC에서는동시에여러 thread 들이 gc를수행하기때문에, gc에소요되는시간이낮아진다. 이 GC 방법은앞에서설명한전통적인 GC방법으로 Minor GC 에 Scavenge를, Full GC에 Mark & compact 알고리즘을사용하는방법이다. 이알고리즘은이미앞에서설명했기때문에별도의설명은생략한다. JDK 1.4에서부터새로적용되는 GC방법은 Parallel GC와 Concurrent GC 두가지방법이있다. Parallel GC는 Minor GC를좀더빨리하게하는방법이고 (Throughput 위주 ) Concurrent GC는 Full GC시에시스템의멈춤 (Pause) 현상을최소화하는 GC방법이다. Parallel GC가언제나유익한것은아니다. 앞에서도말했듯이 1 CPU 에서는동시에여러개의 thread를실행할수없기때문에오히려 Parallel GC가 Default GC에비해서느리다. 2 CPU에서도 Multi thread에대한지원이나계산등을위해서 CPU Power가사용되기때문에, 최소한 4 CPU, 256M 정도의메모리를가지고있는 HW에서 Parallel GC가유용하게사용된다. Parallel GC는크게두가지종류의옵션을가지고있는데, Lowpause 방식과 Throughput 방식의 GC방식이있다. Solaris 기준에서 Low-pause Parallel GC는 - 12 www.bea.co.kr
Bea Enterprise Solution Technical News XX:+UseParNewGC 옵션을사용한다. 이모델은 Old 영역을 GC할때다음에설명할 Concurrent GC 방법과함께사용할수있다. 이방법은 GC가일어날때빨리 GC하는것이아니라 GC가발생할때 Application이멈춰지는현상 (pause) 를최소화하는데역점을뒀다. Throughput 방식의 Parallel GC는 -XX:+UseParallelGC (Solaris 기준 ) 옵션을이용하며 Old 영역을 GC할때는 Default GC (Mark and compact) 방법만을사용하도록되어있다. Minor GC가발생했을때, 되도록이면빨리수행하도록 throughput에역점을두었다. 그외에도 Parallel GC를수행할때동시에몇개의 Thread를이용하여 Minor영역을 Parallel GC할지를결정할수있는데, - XX:ParallelGCThreads=<desired number> 옵션을이용하여 Parallel GC에사용되는 Thread의수를지정할수있다. 3) Concurrent GC 앞에서도설명했듯이, Full GC 즉 Old 영역을 GC하는경우에는그시간이길고 Application이순간적으로멈춰버리기때문에, 시스템운용에문제가된다. < 그림 6> 에서와같이 Application이수행중일때 ( 붉은라인 ) Full GC를위한작업을수행한다 (Sweep, mark). Application을멈추고수행하는작업은일부분 (initial-mark, remark 작업 ) 만을수행하기때문에, 기존 Default GC 의 Mark & Sweep Collector에비해서 Application이멈추는시간이현저하게줄어든다. Solaris JVM에서는 -XX:+UseConcMarkSweepGC Parameter 를이용해세팅한다. 4) Incremental GC (Train GC) Incremental GC 또는 Train GC라고도불리는 GC방법은 JDK 1.3에서부터지원된 GC방법이다. 앞에서설명한 Concurrent GC 와비슷하게, 의도자체는 Full GC 에의해서 Application이멈추는시간을줄이고자하는데있다. Incremental GC의작동방법은간단하다. Minor GC가일어날때마다 Old 영역을조금씩 GC를해서 Full GC 가발생하는횟수나시간을줄이는방법이다. 그래서 JDK 1.4부터제공하는 Concurrent GC는기존의이런 Full GC 의단점을보완하기위해서 Full GC 에의해서 Application 이멈추어지는현상을최소화하기위한 GC방법이다. Full GC 에소요되는작업을 Application을멈추고진행하는것이아니라, 일부는 Application이돌아가는단계에서수행하고, 최소한의작업만을 Application이멈췄을때수행하는방법으로 Application이멈추는시간을최소화한다. < 그림 7. Incremental GC 개념도 > < 그림 7> 에서보듯이왼쪽의 Default GC는 Full GC 가일어난후에나 Old 영역이 Clear 된다. 그러나, 오른쪽의 Incremental GC를보면 Minor GC 가일어난후에, Old 영역이일부 Collect 된것을볼수있다. < 그림 6. Concurrent GC 개념도 > Incremental GC를사용하는방법은 JVM 옵션에 -Xinc 옵션을사용하면된다. Incremental GC는많은자원을소모하고, Minor GC 를자주일으키고, 그리고 Incremental GC를사용한다고 Full GC가없어지거나그횟수가획기적으로줄어드는것은아니다. 오히려느려지는경우가많다. 필히테스트후에사용하도록하자. www.bea.co.kr 13
Default GC이외의알고리즘은 Application의형태나 HW Spec(CPU수, Hyper threading 지원여부 ), 그리고 JVM 버전 (JDK 1.4.1이냐 1.4.2 냐 ) 에따라서차이가매우크다. 이론상으로는실제로성능이좋아보일수있으나, 운영환경에서는여러요인으로인해서기대했던것만큼의성능이안나올수있기때문에, 실환경에서미리충분한테스트를거쳐서검증한후에사용해야한다. 5. GC 로그의수집과분석방법 JVM 에서는 GC 상황에대한로그를남기기위해서옵션을제공하고있다. Java 옵션에 -verbosegc라는옵션을주면되고 HP Unix의경우 -verbosegc -Xverbosegc 옵션을주면좀더자세한 GC정보를얻을수있다. GC 정보는 stdout 으로출력이되기때문에 > (redirection) 등을이용해서 file에저장해놓고분석할수있다. 타낸다. Heap size after GC는 GC가발생한후에 Heap의사용량이다. Minor GC 가발생했을때는 Eden과 Survivor 영역이 GC가되므로 Heap size after GC는 Old 영역의용량과유사하다.(Minor GC 에서 GC되지않은하나의 Survivor 영역내의 Object 들의크기도포함해야한다.) Total Heap Size는현재 JVM이사용하는 Heap Memory 양이다. 이크기는 Java에서 -ms와 -mx 옵션으로조정이가능한데. 예를들어 -ms512m -mx1024m로해놓으면 Java Heap은메모리사용량에따라서 512~1024m 사이의크기에서적절하게늘었다줄었다한다. ( 이늘어나는기준과줄어드는기준은 (-XX:MaxHeapFreeRatio와 -XX:MinHeapFreeRation를이용해서조정할수있으나 JVM vendor에따라서차이가나기때문에각 vendor별 JVM 매뉴얼을참고하기바란다.) Parameter에대한이야기는추후에좀더자세히하도록하자. Example) java -verbosegc MyApplication 그다음값은 GC 에소요된시간이다. 그럼실제로나온 GC 로그를어떻게보는지를알아보자. [GC 40549K->20909K(64768K), 0.0484179 secs] [GC 41197K->21405K(64768K), 0.0411095 secs] [GC 41693K->22995K(64768K), 0.0846190 secs] [GC 43283K->23672K(64768K), 0.0492838 secs] [Full GC 43960K->1749K(64768K), 0.1452965 secs] [GC 22037K->2810K(64768K), 0.0310949 secs] [GC 23098K->3657K(64768K), 0.0469624 secs] [GC 23945K->4847K(64768K), 0.0580108 secs] GC Time Total Heap Size Heap size after GC Heap size before GC < 그림 8. 일반적인 GC 로그, Windows, Solaris> Full GC < 그림 8> 의 GC로그를보면 Minor GC가일어날때마다약 20,000K 정도의 Collection이일어난다. Minor GC 는 Eden과 Suvivor 영역하나를 GC하는것이기때문에 New/Young 영역을 20,000Kbyte 정도로생각할수있다. Full GC일때를보면약44,000Kbyte에서 1,749Kbyte로 GC가되었음을볼수있다. Old 영역에큰데이타가많지않은경우이다. Data 를많이사용하는 Application의경우전체 Heap이 512이라고가정할때, Full GC 후에도 480M 정도로유지되는경우가있다. 이런경우에는실제로 Application에서 Memory를많이사용하고있다고판단할수있기때문에전체 Heap Size를늘려줄필요가있다. 이렇게수집된 GC로그는다소보기가어렵기때문에, 좀더쉽게분석할수있게하기위해서 GC로그를 awk 스크립트를이용해서정제하면분석이용이하다. < 그림 8> 는 GC로그결과를모아놓은내용이다. ( 실제로는 Application의 stdout으로출력되는내용과섞여서출력된다.) Minor GC는 [GC 로표기되고, Full GC는 [Full GC 로표기된다. 그다음값은 Heap size before GC인데, GC 전에 Heap 사용량 (New/Young 영역 + Old 영역 + Perm 영역 ) 의크기를나 < 표 2. gc.awk 스크립트 > BEGIN{ printf( Minor\tMajor\tAlive\tFree\n ); } { 14 www.bea.co.kr
Bea Enterprise Solution Technical News if( substr($0,1,4) == [GC ){ split($0,array, ); printf( %s\t0.0\t,array[3]) split(array[2],barray, K ) before=barray[1] after=substr(barray[2],3) reclaim=before-after printf( %s\t%s\n,after,reclaim) } if( substr($0,1,9) == [Full GC ){ split($0,array, ); printf( 0.0\t%s\t,array[4]) split(array[3],barray, K ) before = barray[1] after = substr(barray[2],3) reclaim = before - after printf( %s\t%s\n,after,reclaim) } next; } 이스크립트를작성한후에 Unix 의 awk 명령을이용해서 % awk -f gc.awk GC 로그파일명을실행하면아래 < 표 3> 와같이정리된형태로 GC 로그만추출하여보여준다. < 표 3. gc.awk 스크립트에의해서정재된로그 > Minor Major Alive Freed 0.0484179 0.0 20909 19640 0.0411095 0.0 21405 19792 0.0846190 0.0 22995 18698 0.0492838 0.0 23672 19611 0.0 0.1452965 1749 42211 0.0310949 0.0 2810 19227 0.0469624 0.0 3657 19441 0.0580108 0.0 4847 19098 Minor와 Major는각각 Minor GC 와 Full GC가일어날때소요된시간을나타내며, Alive 는 GC 후에남아있는메모리양, 그리고 Freed 는 GC 에의해서 collect 된메모리양이다. 이로그파일은 excel 등을이용하여그래프등으로변환해서보면좀더다각적인분석이가능해진다. JDK 1.4에서부터는 -XX:+PrintGCDetails 옵션이추가되어서좀더자세한 GC정보를수집할수있다. HP JVM 의 GC Log 수집 HP JVM 은전체 heap 뿐아니라 -Xverbosegc 옵션을통해서 Perm, Eden, Old등의모든영역에대한 GC정보를좀더정확하게수집할수있다. Example) java -verbosegc -Xverbosegc MyApplication <-- (HP JVM Only) HP JVM 의 GC 정보는 18개의필드를제공하는데그내용을정리해보면 < 표 4> 와같다. <GC : %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16 %17 %18 > < 표 4. HP JVM GC 로그필드별의미 > 필드의미 %1 GC가일어난이유를나타냄 -1:Minor GC 0~6 : Full GC (0:Call to System.gc, 1:Old Generation Full,2: Perm Generation Full,3:Train Generation Full,4:Old generation expanded on last scavenge,5:old generation tool full to scavenge,6:fullgcalot) %2 GC가시작된시간 (Application이시작된시간을기준으로 sec) %3 GC invocation. Counts of Scavenge and Full GCs are maintained separately %4 Size of the object allocation request that forced the GC in bytes %5 Tenuring threshold - determines how long the new born object remains the New Generation %06 %07 %08 Eden Before After Capacity %09 %10 %11 Survivor Generation Before After Capacity %12 %13 %14 Old Generation Before After Capacity %15 %16 %17 Perm Generation Before After Capacity %18 Time taken in seconds to finish the gc www.bea.co.kr 15
이로그를직접보면서분석하기는쉽지가않다. 그래서, HP 에서는좀더 Visual한환경에서분석이가능하도록 HPJtune이라는툴을제공한다. 다음 URL 에서다운로드받을수있다. http://www.hp.com/products1/unix/java/java2/hpjtune/i ndex.html 를때는 heap을늘리고, 남을때는 heap을줄이는 heap growing 과 shirinking 작업을수행하는데, 메모리변화량이큰애플리케이션이아니라면이 min heap size와 max heap size는동일하게설정하는것이좋다. 일반적으로 1GB 까지의 Heap을설정하는데에는문제가없으나, 1GB 가넘는대용량메모리를설정하고자할경우에는별도의 JVM 옵션이필요한경우가있기때문에미리자료를참고할필요가있다. IBM AIX JVM의경우 %export LDR_CNTRL=MAXDATA=0x10000000 %java -Xms1500m -Xmx1500m MyApplication 2) Perm size 조정옵션 Perm Size는앞에서도설명했듯이, Java Application 자체 (Java class etc..) 가로딩되는영역이다. J2EE application의경우에는 application 자체의크기가큰편에속하기때문에, Default로설정된 Perm Size로는 application class가 loading되기에모자란경우가대부분이어서 WAS start초기나, 가동초기에 Out Of Memory 에러를유발하는경우가많다. PermSize는 -XX:MaxPermSize=128m 식으로지정할수있다. 일반적으로 WAS 에서 PermSize는 64~256m 사이가적절하다. < 그림 9. HP Jtune 을이용해서 GC 후 Old 영역의변화추이를모니터링하는화면 > 6. GC 관련 Parameter GC관련설정값을보기전에앞서서 -X와 -XX 옵션에대해서먼저언급하자. 이옵션들은표준옵션이아니라, 벤더별 JVM 에서따로제공하는옵션이기때문에, 예고없이변경되거나없어질수있으므로, 사용전에미리 JVM 벤더홈페이지에서체크한후사용해야한다. 1) 전체 Heap Size 조정옵션전체 Heap size는 -ms 와 -mx 로 Heap 사이즈의영역을조정할수있다. 예를들어 -ms512m -mx1024m 로설정하면 JVM 은전체 Heap size를 application의상황에따라서 512m~1024m byte 사이에서사용하게된다. < 그림 2> 의 Total heap size 메모리가모자 3) New 영역과 Old 영역의조정 New 영역은 -XX:NewRatio=2에의해서조정이된다. NewRatio Old/New Size의값이다. 전체 Heap Size가 768일때, NewRatio=2이면 New 영역이 256m, Old 영역이 512m 로설정이된다. JVM 1.4.X에서는 -XX:NewSize=128m 옵션을이용해서직접 New 영역의크기를지정하는것이가능하다. 4) Survivor 영역조정옵션 -XX:SurvivorRatio=64 (eden/survivor 의비율 ) 64 이면 eden 이 128m일때, survivor 영역은 2m가된다. 5) -server와 -client 옵션 JVM 에는일반적으로 server와 client 두가지옵션을제공한다. 결론만말하면 server 옵션은 WAS와같은 Server환경에최적화 16 www.bea.co.kr
Bea Enterprise Solution Technical News 된옵션이고, client옵션은워드프로세서와같은 client application 에최적화된옵션이다. 언뜻보기에는단순한옵션하나로보일수있지만, 내부에서돌아가는 hotspot compiler에대한최적화방법과메모리구조자체가아예틀리다. -server 옵션 server용 application 에최적화된옵션이다. Server application 은 boot up 시간보다는 user에대한 response time이중요하고, 많은사용자가동시에사용하기때문에 session등의 user data를다루는게일반적이다. 그래서 server 옵션으로제공되는 hotspot compiler는 java application을최적화해서빠른 response time 을내는데집중되어있다. GC 방식에대한옵션 GC 방식에대한옵션은앞에서도설명했지만, 일반적인 GC방식이외에, Concurrent GC, Parallel GC, Inceremental GC와같이추가적인 GC Algorithm이존재한다. 옵션과내용은앞장에서설명한 다양한 GC알고리즘 을참고하기바란다. 7. JVM GC 튜닝그러면이제부터지금까지설명한내용을기반으로실제로 JVM 튜닝을어떻게하는지알아보도록하자. STEP 1. Application의종류와튜닝목표값을결정한다. 또한메모리모델역시, 서버의경우에는특정사용자가서버운영시간동안계속서버를사용하는게아니기때문에 (Login하고, 사용한후에는 Logout되기때문에..) 사용자에관련된객체들이오래지속되는경우가드물다. 그래서상대적으로 Old 영역이작고 New 영역이크게배정된다. < 그림 10. 참조 > -client 옵션 client application은워드프로세서처럼혼자사용하는 application 이다. 그래서 client application은 response time보다는빨리기동되는데에최적화가되어있다. 또한대부분의 client application 을구성하는 object 는GUI Component와같이 application이종료될때까지남아있는 object 의비중이높기때문에상대적으로 Old 영역의비율이높다. JVM 튜닝을하기위해서가장중요한것은 JVM 튜닝의목표를설정하는것이다. 메모리를적게쓰는것이목표인지, GC 횟수를줄이는것이목표인지, GC에소요되는시간이목표인지, Application 의성능 (Throughput or response time) 향상인지를먼저정의한후에. 그목표치에근접하도록 JVM Parameter를조정하는것이필요하다. STEP 2. Heap size와 Perm size를설정한다. -ms 와 -mx 옵션을이용해서 Heap Size를정한다. 일반적으로 server application 인경우에는 ms와 mx 사이즈를같게하는것이 Memory의 growing과 shrinking 에의한불필요한로드를막을수있어서권장할만하다. < 그림 10. -server와 -client 옵션에따른 JVM Old 와 New영역 > 이두옵션은가장간단한옵션이지만, JVM 의최적화에아주큰부분을차지하고있는옵션이기때문에, 반드시 Application의성격에맞춰서적용하기바란다. ( 참고로, SUN JVM은 default가 client, HPJVM는 default가 server로세팅되어있다.) ms와 mx 사이즈를다르게하는경우는 Application 의특정시간대에 memory 사용량이많은 Application 에효과적이다. PermSize는 JVM vendor에따라다소차이가있으나일반적으로 16m 정도이다. Client application의경우에는문제가없을수있지만, J2EE Server Application의경우 64~128m 사이로사용이된다. Heap Size와 Perm Size는아래과정을통해서적정수치를얻어가야한다. STEP 3. 테스트 & 로그분석. JVM Option에 GC 로그를수집하기위한 -verbosegc 옵션을적용한다. (HP의경우 -Xverbosegc 옵션을적용한다.) LoadRunner나 MS Stress( 무료로 MS 의홈페이지에서다운로 www.bea.co.kr 17
드받을수있다.) 와같은 Stress Test툴을통해서 Application에 Stress를줘서그 log 를수집한다. 튜닝에있어서가장중요한것은목표산정이지만, 그만큼이나중요한것은실제 Tuning한 Parameter가 Application에어떤영향을주는지를테스트하는방법이매우중요하다. 그런의미에서적절한 Stress Tool의선정과, Stress Test 시나리오는정확한 Tuning을위해서매우중요한요인이다. Perm size 조정아래 < 그림 11> 은 HP JVM에서 -Xverbosegc 옵션으로수집한 GC log 를 HP Jtune 을통해서 graph로나타낸그래프이다. 그림을보면 Application이 startup되었을때 Perm 영역이 40m에서시간이지난후에도 50m 이하로유지되는것을볼수있다. 특별하게동적 classloading 등이수십 m byte가일어나지않는등의큰변화요인이없을때, 이 application의적정 Perm 영역은 64m 로판단할수있다. 여기서 STEP 1에서설정한 AP Tuning의목표치를참고해야하는데, Full GC 가길게일어나서 Full GC 에수행되는시간을줄이고자한다면 Old 영역을줄이면 Full GC 가일어나는횟수는늘어나고, 반대로 Full GC 가일어나는시간을줄어들것이다. 반대로 Full GC 가일어나는횟수가많다면, Old 영역을늘려주면 Full GC 가일어나는횟수는상대적으로줄어들것이고반대로 Full GC 수행시간이늘어날것이다. 특히 Server Application의경우 Full GC가일어날때는 JVM 자체가멈춰버리기때문에, < 그림 12> 의 instance는 14시간동안총 7 번시스템이멈추고, 그때마다 2.5~6sec가량시스템이 response 를못하는상태가된것이다. 그래서멈춘시간이고객이납득할만한시간인지를판단해야하고, 거기에적절한 Tuning을해야한다. Perm size < 50M Server Application에서 Full GC를적게일어나게하고, Full GC 시간을양쪽다줄이기위해서는 Old 영역을적게한후에, 여러개의 Instance를동시에띄어서 Load Balancing을해주면, Load가분산되기때문에 Full GC 가일어나는횟수가줄어들테고, Old 영역을줄였기때문에, Full GC에드는시간도줄어들것이다. 또한각각의 Full GC 가일어나는동안하나의서버 instance가멈춰져있어도, Load Balancing이되는다른서버가 response를하고있기때문에, Full GC로인한 Application이멈추는것에의한영향을최소화할수있다. < 그림 11. GC 결과중 Perm 영역그래프 > GC Time 수행시간분석다음은 GC에걸린시간을분석해보자. 앞에강좌내용에서도설명했듯이 GC Tuning에서중요한부분중하나가 GC에소요되는시간특히 Full GC 시간이다. Full GC 지금부터분석해볼 Log 는모 의물류시스템의 WAS 시스템 GC Log 이다. HP JVM 을사용하며, -server -ms512m -mx512m 옵션으로기동되는시스템이다. 250000sec~300000sec: 약 14 시간 < 그림 12. GC 소요시간 > < 그림 12> 를보면 Peak 시간 ( 첫번째동그라미 ) 14 시간동안에 Full GC( 동그란점 ) 가 7번일어난것을볼수있다. 각각에걸린시간은 2.5~6sec 사이이다. 데이타에따라서 GC Tuning을진행한후에는다시 Stress Test 를진행해서응답시간과 TPS(Throughput Per Second) 를체크해서어떤변화를주었는지를반드시체크해봐야한다. 18 www.bea.co.kr
Bea Enterprise Solution Technical News 인판단내용은아래와같다. Full GC 향상포인트 GC Algorithm 비고 Old 영역의최소메모리요구량 Performance Parallel GC JVM 1.4.2 이상 4CPU 이상 ( 속도 ) 중시 Responsiveness Concurrent GC JVM 1.4.2 이상 4CPU 이상 ( 응답성 ) 중시 Responsiveness Incremental GC JVM 1.4.2 이하또는 4CPU ( 응답성 ) 중시 미만 월요일근무시간 화요일근무시간 일반 Default GC JVM 1.4.2 이하또는 4CPU 미만 < 그림 13. GC후의 Old 영역 > < 그림 13> 은 GC 후에 Old 영역의메모리변화량을나타낸다금요일업무시간에메모리사용량이올라가다가. 주말에가서완만한곡선을그리는것을볼수있다. 월요일근무시간에메모리사용량이매우많고, 화요일에도어느정도메모리사용량이있는것을볼수있다. 월요일에메모리사용량이많은것을볼때, 이시스템의사용자들이월요일에시스템사용량이많을수있다고생각할수있고, 또는다른주의로그를분석해봤을때이주만월요일사용량이많았다면, 특별한요인이나 Application 변경등이있었는지를고려해봐야할것이다. 이렇게 Parameter를변경하면서테스트를진행하고, 다시변경하고테스트를진행하는과정을거쳐서최적의 Parameter와 GC Algorithm을찾아내는것이 JVM 의메모리튜닝의이상적인절차이다. 지금까지 JVM 의메모리구조와 GC 모델그리고 GC 튜닝에대해서알아보았다. 정리하자면 GC 튜닝은 Application의구조나성격그리고, 사용자의이용 Pattern 에따라서크게좌우되기때문에, 얼마만큼의 Parameter를많이아느냐보다는얼마만큼의테스트와로그를통해서목표값에접근하느냐가가장중요하다. 이그래프만을봤을때 Full GC 가일어난후에도월요일근무시간을보면 Old 영역이 180M를유지하고있는것을볼수있다. 이시스템의 Full GC 후의 Old 영역은 80M~180M를유지하는것을볼수있다. 그래서이시스템은최소 180M이상의 Old 영역을필요로하는것으로판단할수있다. STEP 4. Parameter 변경. STEP 3에서구한각영역의허용범위를기준으로 Old 영역과 New 영역을적절하게조절한다. PermSize와 New영역의배분 (Eden, Survivor) 영역등을조정한다. PermSize는대부분 Log에서명확하게나타나기때문에, 크게조정이필요가없고 New 영역내의 Eden과 Survivor 는거의조정하지않는다. 가장중요한것은 Old 영역과 New 영역의비율을어떻게조정하는가가관건이다. 이비율을결정하면서, STEP 1에서세운튜닝목표에따라서 JVM 의 GC Algorithm을적용한다. GC Algorithm을결정하는기본적 www.bea.co.kr 19