G1 Concept

  • G1에서 연속적인 메모리 공간을 region이란 이름의 고정된 크기로 나눈다.
  • eden, survivor, old 영역은 고정된 크기로 나눈 이 region을 사용한다. region이 곧 eden이거나 survivor, old일 수 있다.
  • 기본 region 목표 수치는 2048개(2K)개의 공간으로 나눌 수 있도록 한다. 만약 8G가 Java Heap 최대 크기라면 한 region의 크기는 4MB가 되겠다. (8192MB/2048 = 4MB)
  • region 공간은 1MB ~ 32MB 사이로 -XX:G1RegionSize 옵션을 이용해 조정 가능하지만, 사용자가 직접 튜닝하는 것은 추천하지 않는다.
  • eden, survivor, old 이외에도 2가지 다른 타입의 region이 존재한다. Humongous region과 Available / Unused region이다.
    • Humongous region은 객체의 크기가 큰 경우 사용하는 영역다. 만일 객체가 region 영역의 크기보다 1/2 (논문에선 1/3)보다 큰 경우 Humongous region을 사용하도록 한다.
    • Avaialable / Unused region은 아직 사용하지 않은 영역을 의미한다.
    • Humongous region에 대한 GC 동작은 최적화 되어 있지 않다. 따라서 큰 객체 Size가 G1 GC를 사용하는데 문제라면 왜 큰 객체가 문제가 되는지 프로그램을 분석하는게 순서가 되겠다. 또한 큰 객체 사용의 또 다른 문제는 Java에서 큰 객체를 할당하는 것은 일반적인 크기의 객체를 할당하는 것보다 Overhead가 크므로 프로그램 설계에 문제가 없는지 봐야 한다.

 

 

 

G1 GC 수행 단계

  • G1 GC 수행 과정은 Evacuation Pauses(=Minor GC), Concurrent Cycle, Mixed GC가 있다.

  • Evacuation Pauses(=Minor GC)

    • Evacuation Pauses(=Minor GC)일 때 eden과 survivor에 있는 유효 객체(Live objects)를 적절한 region을 찾아 대피시키도록(Copying) 한다.

    • Evacuation Pauses(=Minor GC)일 때 GC 대상의 region 선택은 사용자가 옵션으로 지정한 pause time과 G1 GC 내부에서 사용하는 휴리스틱 알고리즘에 의해 선택된다. 그 이유는 G1 GC의 중요한 목표 중 하나는 실시간성 향상에 있기 때문이다.(Hard real-time이 아닌 휴리스틱 알고리즘에 의한 Soft real-time Goal이다.)

    • Evacuation Pauses는 빨리 완수하기 위해 JVM에서 Multi-threaded로 동작한다.

    • Young Generation Stop-the-world 구간이다. (CMS와 다름)

    • Survivor region은 liveness objects를 판단하기 위해, Eden region은 pause time을 예측하는데 사용된다.

    • minor GC 때마다 Eden과 Survivor 영역 크기는 변경될 수 있다.(CMS와 다름. Parallel OLD GC에서는 Adpatable하게 사이즈가 변경가능한 옵션이 있던것으로 기억하는데, CMS도 있는지 잘 모르겠음. 보통 쓰지 않는 기능...)

    • Eden에 있는 live object는 Survivor 영역으로, Survivor from은 Survivor to로, Survivor to는 OLD 영역으로 이동한다는 내용이 있는 반면, 유효 객체(live objects)가 Available/Unused region으로 이동되고, survivor region으로 바뀐다는 내용도 있다. (전자가 맞는 듯 하다. 기존 Generation 기반 GC 개념 자체를 바꿀 필요가 없을 테니까..)

    • 논문에서는 첫 Evacuation Pauses는 일정 용량이상 차면 수행 되고, 그 이후에는 사용자가 지정한 pause duration과 per-byte copying Cost에 의해 결정된다고 한다. 얼마나 많은 Live object를 to-survivor regions에 복사할지 추정하는데 단위 바이트당 소요될 Cost와 pause duration P의 곱이 제한 시간 내 복사할 수 있는 용량으로 산정해서 동작한다.

    • 각 region에는 Live Data Counting 정보를 가지고 있다. 이 정보를 바탕으로 region 영역이 먼저 Garbage 되어야 하는지 결정된다.(그래서 이름이 Garbage First, G1 이다).

    • External Root Scanning: gc thread들이 registers, thread stacks에서 root 노드를 검색하는 단계

    • Update Remembered Sets: RSet 정보를 갱신하는 단계

      • Processed Buffers: worker thread가 얼마나 많은 update 버퍼 정보를 갱신했는지 보여준다.

    • Scan Rsets: 업데이트 된 Rset 정보를 기반으로 region을 향해 가진 reference를 가진 객체들을 탐색한다.

    • Object Copy: Scan Rsets에서 탐색한 객체들을 복사하기 시작한다. Eden에 있는 객체들을 from-space로, from-space에 있는 객체들을 to-space로, to-space에 있던 객체들을 Old 영역으로 복사한다.

    • Termination: GC thread들은 객체 탐색 및 객체 복사의 일이 끝나면 Termination 단계에 들어간다. Task 처리의 로드밸런싱 효율을 높이기 위한 방법으로 Work-stealing 기법을 사용하고 있다.

    • Parallel Worker Other time: 위에서 언급한 일 이외의 다른 부수적인 일을 처리한 시간
       

  • Concurrent Cycle

    • -XX:InitiatingHeapOccupancyPercent (IHOP) 에서 정한 수치가 넘어가면 동작한다.

    • OLD 영역을 GC하기위한 전초 작업이다.

      • initial mark: multi-threaded로 동작하며, minor GC때 수행 한다. (CMS와 다름. CMS에서 initial mark는 stop-the-world 구간이다.)

      • Root region Scanning: multi-threaded로 동작하며, Application과 Concurrent하게 동작한다. 이때 Old 영역으로 reference를 가진 survivor-regions을 검색한다. 이 단계가 끝나야 Evacuation Pauses(Minor GC)가 동시에 실행될 여지가 발생한다.(Survivor regions 영역은 Evacuation Pauses(Minor GC)에서도 탐색하기 때문)

      • Concurrent marking: multi-threaded로 동작하고, Application과 Concurrent하게 동작한다. 모든 rechable / live 객체들을 마킹한다. 이 때부터 Evacuation Pauses와 동시에 실행 가능하다.

        • GC 로그 예) [GC concurrent-mark-start]
                           [GC concurrent-mark-end, ...

      • Remark: Stop-the-world 구간이다. multi-threaded로 동작한다. marking 작업을 마무리.

        • GC 로그 예) [GC remark ....

      • Cleanup: Partly Stop-the-world 구간이다. multi-threaded로 동작한다. region 영역의 liveness 정보를 갱신하고, 적절한 free region을 식별한다. 논문에 의하면 Cleanup 할 때, 각 region의 GC 효율을 기준으로 정렬하는데(G1 first, cost efficiency), GC 효율 측정 factor에 remember set의 size등을 고려하는데 이러한 작업을 하기 위한 기본 데이터 값들을 정리한다.
        (Updates region liveness and identifies completely free regions along with remembered set scrubbing)

        • GC 로그 예) [GC cleanup, ...

      • Concurrent-Cleanup: empty region 자료구조를 Reset하고, available/Unused regions list에 추가한다.

        • GC 로그 예) [GC concurrent-cleanup-start]
                            [GC concurrent-cleanup-end, ...

  • Mixed GC

    • Mixed GC일 때 Young영역과 Old 영역을 Garbage collection 한다.(단어에서 의미하듯 Mixed이다.)

    • OLD region 영역의 GC 선택 기준은 liveness를 기준으로 판단한다. Garbage Collection 효율을 높이기 위해 liveness가 높은 것은 재사용될 가능성이 높다고 판단하기에 liveness가 적은 것을 GC하도록 한다.(따라서 Garbage First, G1이라는 이름이 붙었다.)

    • Mixed GC는 기본적으로 8회 수행되도록 되어 있다. 1회의 Mixed GC에 모든 OLD 영역이(Old regions) Garbage collection되지 않는다. 한번에 Garbage를 정리하기에 Cost가 매우 크기 때문이다.
    • minor GC 처럼 Eden과 Survivor 영역 크기는 변경될 수 있다.

    • Mixed GC는 Evacuation Pauses때 수행하는 단계와 동일하다. Evacuation Pauses인데 OLD region을 추가적으로 GC 하는 것이다. Mixed GC = Evacuation Pauses(Young GC + OLD GC)

    • Mixed GC 때 선택되는 CSet은(Old regions) -XX:G1MixedGCCountTarget (defaults to 8) -XX:G1OldCSetRegionThresholdPercent 에 영향받는다. OLD 영역에 관한 CSet Tuning과 관련있다.

    • Mixed GC 선택 대상 결정은 -XX:G1MixedGCLiveThresholdPercent,-XX:G1HeapWastePercent에 영향 받는다.

G1에서 사용하는 중요 자료구조(G1's data structures)

  • Remember Set (RSet)

    • reference를 가진 Object들이 어느 Region에 있는지 알기 위해 사용하는 자료구조다. (이 Reference를 왜 알아야 하냐면 Live Object을 알기 위함이다. Object가 가진 Reference의 Origin을 왜 알아야 하는지는 Baker's Incremental GC 알고리즘을 이해하자. 참고자료는 Baker's Incremental Copying Collector 알고리즘, 간략히 이야기하면 Reference를 가진 Objects를 찾아 live object를 복사하는 알고리즘이다. Baker's에서는 live object 검색 시간이 O(n)*rootset 의 시간 복잡도가 걸리지만, Rset을 사용해서 개선 시킬 수 있다.)

    • GC 로그에서 이 Reference 정보를 갱신(Update)하고 검색하는데 소요되는 시간을 보여준다.

  • Collection Set (CSet)

    • GC가 수행될 Region의 모음.

    • GC 로그에서 CSet을 선택하고, Processing 후 CSet을 해제하는데 걸린 시간을 볼 수 있다. Evacuation Pauses와 Mixed GC할 때 사용하는 자료구조이다.

G1 옵션

  • -XX:+UseG1GC 필수, -Xms, -Xmx 는 Optional

  • -XX:MaxGCPauseMillis: default 200ms(확인이 필요)

  • -XX:InitiatingHeapOccupancyPercent (aka IHOP): 기본값은 자바 Heap의 45%, Concurrent Cylce의 시작 시기를 조정할 수 있는 옵션

  • -Xmn, -XX:NewSize/-XX:MaxNewSize/-XX:NewRatio, -XX:SurvivorRatio Young 영역 공간에 대한 옵션 Tuning은 G1의 휴리스틱 동작을 비활성화한다(Disable adaptive G1's heuristic algorithm). 따라서 설정하지 않는 것이 좋다.

  • -XX:G1MixedGCLiveThresholdPercent (defaults to 65): – OLD region내 live object가 이 옵션 이상 값으로 존재한다면 GC 대상에서 제외한다.
  • -XX:G1HeapWastePercent (defaults to 10): – 얼마나 많은 region이 waste되어도 용납할지 결정한다. Heap을 낭비해도 좋다고 판단하는 값. mixed cycle의 종료 시점을 결정한다.

  •  -XX:GCPauseIntervalMillis =200 (for a pause interval target of 200ms) : G1 GC 주기 조정


G1 GC Tuning

  • GC가 Application의 병목현상의 원인인지부터 확인한다. GC가 Application 동작에 문제를 일으킨다면, GC Tuning을 한다.

  • GC가 Application의 병목현상이 원인인지는 GC로그를 보고 판단한다.

  • GC Pauses 최대, 평균 시간, GC의 동작 횟수(얼마나 자주 동작하는가)를 확인한다.  

  • GC 로그에서 각 GC 동작 스텝의 user, sys, real time 로그를 확인한다.

  • G1 GC의 경우 -XX:+PrintAdaptiveSizePolicy 옵션을 사용하면 GC가 수행되는 region 정보를 볼 수 있다.

  • Mixed GC 옵션 Tuning은 다음 4가지 옵션을 고려한다.

    • -XX:G1MixedGCCountTarget (defaults to 8)

    • -XX:G1OldCSetRegionThresholdPercent

    • -XX:G1MixedGCLiveThresholdPercent

    • -XX:G1HeapWastePercent

  • CSet Tuning: CSet의 병목현상은 CSet의 범위를 조정해서 완화시킬 수 있다. Mixed GC 옵션을 활용하여 Tuning한다.

  • RSet Tuning: 의 Tuning은 다음 옵션을 고려한다.

    • -XX:G1RsetUpdatingPauseTimePercent(사용자가 지정한 puase time의 10%): RSet update할 시간 조정

    • XX:+ParallelRefProcEnabled: User time이 오래 걸린다면, Scaling을 의심한다. remark 단계에서 reference processing 시간을 보고 scaling이 잘 안되는 경우 사용.

 

정리

  • 기존 GC가 Space based 동작이라면 G1 GC는 Time based 동작으로 적시에 GC를 수행할 수 있게 되었다.

  • Young 영역에 대한 GC 시작은 사용자가 지정한 Pause time에 의해 휴리스틱하게 결정된다. Young 영역에서 GC할 CSet의 선택도 역시 Pause time에 영향 받는다. GC 수행 종료 시점도 마찬가지로 Pause time에 종속된다.

  • Concurrent Cycle은 OLD 영역을 GC하기 전에 필요한 정보를(region별 gc cost, 객체 liveness count) 얻기 위해 수행한다. Mixed GC의 전 작업이다.

  • OLD 영역에 대한 GC 수행 시작은 IHOP이 결정한다.

  • OLD 영역 GC 수행시 선택될 CSet은 다음 두 옵션에 의해 영향 받는다.

    • -XX:G1MixedGCCountTarget (defaults to 8): Mixed GC 최소 수행 작업 횟수

    • -XX:G1OldCSetRegionThresholdPercent (defaults to 10): Mixed GC 수행시 선택할 최대 OLD region 개수, 자바 Heap의 Percentage로 값을 설정한다.

  • CMS의 경우 Eden, Survivor 영역의 크기는 고정되어 있지만, G1은 GC이전과 GC이후에 각 영역의 Size는 변동(Adaptable) 될 수 있다.

  • 기존 Young, OLD 컨셉을 버리고 Region으로 나누고 Region별 live object정도를 판단함으로써 더 명확한 Garbage 객체 결정을 할 수 있게 되었다. 또한 프로그램 구조적으로 Parallel, Concurrent하게 동작하기에 용이한 구조이기에 Multi Processor에 사용하기 적합한 구조이다. 이와 더불어 GC 시점과 대상에 대한 휴리스틱한 알고리즘을 넣음으로써 High allocation Rate, Large Heap을 요구하는 Application의 요구사항을 충족시켜줄 수 있게 되었다.

  • Collection 단계를 Evacuation, Concurrent Cycle, Mixed GC 단계로 나눈 이유: CMS 혹은 Parallel GC같은 기존의 GC 수행 형태는 Minor GC와 OLD GC 이 두 단계로 나눌 수 있다. 최대한 Concurrent 그리고 Parallel하게 동작하기 위해 기존의 OLD GC의 단계를 Concurrent Cycle(GC 객체 검색 및 마킹:Scanning and Mark)과 Mixed GC(GC 수행 및 정리:Evacuation and Cleanup) 이 두 단계로 분리한 것이다. G1 GC에서 Concurrent Cycle은 Minor GC와 동시에 수행이 가능하다.(단 Root region scanning 이후에 가능하다.) 그리고 Concurrent Cycle이 끝나면 이때 Marking한 정보를 기반으로 Mixed GC가 수행된다.

  • Snapshot At The Begging(SATB): 논문에서 SATB란 단어가 나오는데, 이 단어의 의미는 특정 순간의 내용을 기록한다는 의미이다. G1 GC에서는 IHOP이 넘는 그 순간에 Concurrent Cycle을 시작해서 Snapshot을 찍고(OLD 영역의 GC할 대상을 찾아 기록함) Mixed GC에서 SATB에서 정리한 정보를 바탕으로 OLD region garbage collection이 연속(기본 8회) 수행된다. 당연하지만 Mixed GC때 Young 영역의 region도 같이 Garbage collection된다.


Posted by initproc