본문으로 바로가기

Garbage Collection Part2

category Java 개발 이야기 2020. 12. 6. 23:39
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

GC (Garbage Collector)의 방식은 무엇이 있을까


"Garbage Collection Part1"에서 기본적인 GC Process 절차에 대해서 알게 되었다.

이번 포스팅은 GC의 종류 및 방식에 대해서 이어서 진행한다.


GC의 종류

GC는 크게 Minor GC와 Major GC 두가지 종류가 있다.

Minor : Young 영역에서 발생하는 GC

Major : Old 영역이나 Perm 영역에서 발생하는 GC


GC가 발생하거나 객체가 다른 영역으로 이동할 때 병목이 발생하여 성능에 영향을 준다.


핫 스팟 JVM에서는 TLABs(Thread-local allocation Buffers)라는 것을 사용한다. 이를 통해 각 스레드 메모리 버퍼를 사용하면 다른 스레드에 영향을 주지 않는 메모리 할당 작업이 가능하다.

- 에덴 내에 있는 한 영역

- 스레드마다 할당되는 객체의 버퍼, 하나의 스레드가 처리할 수 있는 객체의 최대 크기, 

- 각 스레드마다 로컬에 할당되므로, 동기화에 신경쓰지 않아도 된다.

- 큰 객체를 많이 할당하는 어플리케이션, 에덴의 크기에 비해 상대적으로 스레드의 개수가 많은 어플리케이션은 TLAB 튜닝으로 상당한 이익을 어들 수 있다.



GC의 방식은 5가지가 있다.

1. Serial GC

2. Parallel GC

3. Parallel Old GC

4. CMS (Concurrent Mark & Sweep GC) 

5 G1(Garbage First) GC



https://www.dynatrace.com/resources/ebooks/javabook/reduce-garbage-collection-pause-time/



Serial GC

Java 5, 6에서의 기본 가비지 컬렉트이고, 싱글 스레드로 돌아간다. 위 이미지 첫 번째 이미지를보면 Pause(Stop-the-Wold)시간이 긴 것을 볼 수 있다. 싱글 스레드로 GC를 수행하기 문에 수행 시간이 긴 것을 볼 수 있다.


-XX:+UseSerialGC


Parallel GC

Parallel GC는 Serial GC와 똑같은 원리로 동작하지만 Young 영역의 GC과정을 멀티 스레드로 수행한 다는 점이 차이가 있다. 그래서 Pause시간이 짧은 것을 볼 수 있다.


-XX:+UseParallelGC


Parallel Old GC

위의 의미지에선 언급되진 않았지만 Parallel Old GC는 Old 영역에 대해서도 멀티 스레드로 수행한다. 

Mark-Sweap-compact알고리즘에서 Mark-Summary-Compact 알고리즘을 사용한다.


-XX:+UseParallelOldGC


CMS 


CMS GC는 Young 영역에 대한 GC는 Parallel과 비슷하다, Old영역의 GC는 4가지 단계를 거친다.

1. Initial Mark : 매우 짧은 시간의 Pause시간 동안 GC Root를 가장 먼저 참조하는 객체들을 식별한다. 이 부분은 싱글스레드로 동작한다.


2. Concurrent Mark : 싱글 스레드로 수행되고, Initial Mark 단계에서 식별한 객체가 참조하고 있는 모든 객체들을 추적, 어플리케이션 실행과 동시에 진행된다.


3. Remark : Concurrent Mark단계에서 식발한 객체를 다시 추적한다. 멀티 스레드로 동작하여 pause가 짧다.


4. Concurrent Sweep : 최종적으로 살아있는 객체를 제외한 객체들을 삭제한다. 싱글 스레드로 수행되며 다른 스레드와 동시에 수행되기 때문에 Stop The World가 발생하지않는다. 하지만 Compact 과정이 존재하지 않기 때문에 메모리 단편화가 생겨 Concurrent Mode Failure(CMF) 가 발생할 수 있다. Concurrent Mode Failure는 Old영역에 더 이상 메모리를 할당할 공간이 없을 때 발생하는데 메모리 단편화로 인해 Old 영역의 빈 공간이 충분히 존재함에도 불구하고 크기가 큰 객체를 할당할 수 없는 경우가 생길 수 있다. CMF가 발생하면 강제적으로 Compaction을 수행하므로 'Stop The World' 시간이 다른 GC보다 길어질 가능성이 있다.


-XX:+UseConcMarkSweepGC


G1GC

G1GC는 CMS를 대체하기 위해 만들어졌다. 일반적으로 Young, Old Generation이라는 영역으로 나누어 지지않았고, Region이라는 영역으로 관리한다. CMS과 다르게 Compaction단계를 통해 메모리 단편화를 업앤다.

G1 GC는 Garbage만 있는 Region을 처음에 수거하기 때문에 Garbage First라는 이름이 붙었다.


G1GC의 프로세스에 대해서는 "Oracle G1Gc Getting started"를 참고하였다.



1. G1 Heap Structure

The heap is one memory area split into many fixed sized regions.

Region size is chosen by the JVM at startup. The JVM generally targets around 2000 regions varying in size from 1 to 32Mb. 


Heap을 여러개의 고정된 Region이라는 논리적 단위로 나누어 졌고,

JVM 시작시 Region 사이즈는 결정되고 일반적으로 1~32MB 사이즈에 약 2000개의 리즌으로 나눠진다.


2.G1 Heap Allocation

In reality, these regions are mapped into logical representations of Eden, Survivor, and old generation spaces.

아래 이미지에서 리전은 Eden, Survivor, Old 이 있다.


The colors in the picture shows which region is associated with which role. Live objects are evacuated (i.e., copied or moved) from one region to another. Regions are designed to be collected in parallel with or without stopping all other application threads.

각 색의 리전들은 각각의 Role(Eden, Suvivor, Old)의 역할이 있다. 이 객체는 다른 리즌에서 또다른 리즌으로 옮겨지며, 어플리케이션 중지 없이 다른 리즌으로 모여지도록 설계되어 있다.


As shown regions can be allocated into Eden, survivor, and old generation regions. In addition, there is a fourth type of object known as Humongous regions. These regions are designed to hold objects that are 50% the size of a standard region or larger. They are stored as a set of contiguous regions. Finally the last type of regions would be the unused areas of the heap.

Eden, survivor, old Region으로 할당되고, Humongous regions이라는 것은 할당된 리즌사이즈보다 클 때 사용되는 4번째 region 타입입니다. 마지막영역 (회색)은 사용하지 않는 공간을 나타낸다.


Note: At the time of this writing, collecting humongous objects has not been optimized. Therefore, you should avoid creating objects of this size.


3.

The heap is split into approximately 2000 regions. Minimum size is 1Mb and maximum size is 32Mb. Blue regions hold old generation objects and green regions hold young generation objects.

대략 2000개의 리즌으로 나눠지고 1~32MB 크기로 사용된다.

Note that the regions are not required to be contiguous like the older garbage collectors.

이전 GC처럼 리전은 인접 또는 연속적일 필요가 없다.


4.

Live objects are evacuated (i.e., copied or moved) to one or more survivor regions. If the aging threshold is met, some of the objects are promoted to old generation regions.

처음 메모리에 올라간 객체들은 1개 이상의 survivor Regions로 복사 또는 옮겨지며 만약 age가 한계점에 도다랐으면 Old Generation Region으로 옮겨진다.


This is a stop the world (STW) pause. Eden size and survivor size is calculated for the next young GC. Accounting information is kept to help calculate the size. Things like the pause time goal are taken into consideration.

이때 Stop-the-World가 발생한다. Eden 그리고 survivor의 크기는 다음 발생할 Young GC를 위해 계산되고, 계산된 정보는 Region Size계산을 위해 저장된다.


This approach makes it very easy to resize regions, making them bigger or smaller as needed.

이런 접근 방식을 통해 리즌 사이즈를 더 크게, 또는 적게 요구에 따라 쉽게 재조정 할 수 있다.

 


5.

Live objects have been evacuated to survivor regions or to old generation regions.

생성된 객체들은 survivor 영역 또는 Old generation 영역으로 옮겨진다.


Recently promoted objects are shown in dark blue. Survivor regions in green.

최근 promotion(young -> old)된 객체들은 진한 파랑, 새로 young generation으로 옮겨진 객체는 초록 계열로 옮겨진다.


In summary, the following can be said about the young generation in G1:

- The heap is a single memory space split into regions

- Young generation memory is composed of a set of non-contiguous regions. This makes it easy to resize when needed 

- Young generation garbage collections, or young GCs, are stop the world events. All application threads are stopped for the operation.

- The young GC is done in parallel using multiple threads.

- Live objects are copied to new survivor or old generation regions.


Young Generation GC는 
- Heap은 여러개의 리즌 공간으로 나눠진다.
- young Generation은 연속적이지 않은  region으로 구성된다. 이것은 더 쉽게 사이즈 조정할 할 수 있게 한다.
- Young GC시 Stop-the-world가 일어난다. 모든 어플리케이션 스레드는 종료된다.
- Young GC가 멀티 스레드가 병렬로 실행 된다.
- 살아있는 객체들은 survivor 또는 Old generation 리전으로 옮겨진다.




아래 표는 G1GC에서 Old Generation 단계에 대한 설명을 나타낸다.


Old Generation Collection with G1

CMS와 같이 G1은 Old Generation에서 중지시간을 단축시키기 위해 디자인 되었다.  아래 테이블은 Old Generation에 대해서 G1 Collection의 동작 방법에 대해서 설명한다.


 Phase(단계)

 Description

 1. Initial Mark

Stop the world가 발생한다.

 


This is a stop the world event. With G1, it is piggybacked on a normal young GC. Mark survivor regions (root regions) which may have references to objects in old generation.


여기서 Stop the world 이벤트가 발생, Old Generation에 있는 객체를 참조하고 있는 Survivor Region을 마킹한다.

 2. Root Region Scanning

 

Scan survivor regions for references into the old generation. This happens while the application continues to run. The phase must be completed before a young GC can occur.

Old Generation으로 참조하는 Survivor 리즌을 조회한다. 이때 어플리케이션은 실행되고 있고, 이 단계가 완료되야 Young GC가 수행될 수 있다.

3. Concurrent Marking

 

Find live objects over the entire heap. This happens while the application is running. This phase can be interrupted by young generation garbage collections.

Heap 영역에 있는 모든 살아있는 객체를 조회한다. 어플리케이션이 실행되는 동안 실행되며, 이 단계에서Young GC에 의해 중단될 수 있다.

4. Remark

Stop the world가 발생한다 

 

Completes the marking of live object in the heap. Uses an algorithm called snapshot-at-the-beginning (SATB) which is much faster than what was used in the CMS collector.

Heal 영역에 있는 살아있는 객체 마킹을 완료하고, SATP라는 알고리즘을 사용하여 CMS보다 더 빠르게 동작한다.

 5. Clean up

Stop the world Event and Concurrent

 

  • Performs accounting on live objects and completely free regions. (Stop the world)
  • Scrubs the Remembered Sets. (Stop the world)
  • Reset the empty regions and return them to the free list. (Concurrent)
살아있는 객체를 조회하고, 비어있는 Region을 계산합니다. (Stop the world) 발생
Remembered Set을 정리한다.
Reference를 가진 객체가 어떤 Region에 할당되어 있는지 알기 위한 자료구조
비어있는 Region을 정리하고 Free list에 추가한다. (동시에 실행 )

 (*) Copying

Stop the world가 발생한다

 

    These are the stop the world pauses to evacuate or copy live objects to new unused regions. 
    This can be done with young generation regions which are logged as [GC pause (young)]
    Or both young and old generation regions which are logged as [GC Pause (mixed)].

사용하지 않은 리즌으로 살아 있는 객체를 복사한다

Young Generation에서는 [GC pause (young) ] 구문으로 로깅된다.


6. Initial Marking Phase

Initial marking of live object is piggybacked on a young generation garbage collection. In the logs this is noted as GC pause (young)(inital-mark).


7. Concurrent Marking Phase

If empty regions are found (as denoted by the "X"), they are removed immediately in the Remark phase. Also, "accounting" information that determines liveness is calculated.


비어있는 Region이 발견되면, 그 리즌은 Remark 단계에서 삭제된다.


8. Remark Phase

Empty regions are removed and reclaimed. Region liveness is now calculated for all regions.

비어 있는 리즌들은 제거되고 반환되며, 모든 Region에 대한 liveness가 계산된다.

 



9.Copying/Cleanup Phase

G1 selects the regions with the lowest "liveness", those regions which can be collected the fastest. Then those regions are collected at the same time as a young GC. This is denoted in the logs as [GC pause (mixed)]. So both young and old generations are collected at the same time.


G1 "liveness"가 낮은 리전을 선택하고 모아서 young GC를 수행하고, 리전들을 모아서 수집합니다(compact)

이 부분은 Young, Old Generation이 동시해 수행됩니다.



10. After Copying/Cleanup Phase

The regions selected have been collected and compacted into the dark blue region and the dark green region shown in the diagram.


GC가 일어난 이후에 진한 녹색(최근 Young generation으로 compact), 진한 파랑(최근 Old Generation) Region으로 이동하고 Compact  



    Summary of Old Generation GC

    In summary, there are a few key points we can make about the G1 garbage collection on the old generation.

    • Concurrent Marking Phase
      • Liveness information is calculated concurrently while the application is running.
      • This liveness information identifies which regions will be best to reclaim during an evacuation pause.
      • There is no sweeping phase like in CMS.
    • Remark Phase
      • Uses the Snapshot-at-the-Beginning (SATB) algorithm which is much faster then what was used with CMS.
      • Completely empty regions are reclaimed.
    • Copying/Cleanup Phase
      • Young generation and old generation are reclaimed at the same time.
      • Old generation regions are selected based on their liveness.

Old Generation GC 요약

- Concurrent Marking Phase
Liveness(활성) 정보는 어플리케이션이 실행되는 동안 동시에 계산된다.
각 리전의 활성 정보가 evacuation pause(young gc) 진행되는 동안 최적화가 될 수 있도록 reclaim 한다.
CMS와 같은 sweeping 단계가 존재하지 않는다.
- Remark Phase
CMS에서 사용하고 있는 알고리즘보다 더 빠른 SATP를 사용한다.
완벽하게 비어있는 리즌은 반환된다.
Copying/Cleanup Phase
Old generation 리전은 활성(liveness) 상태에 따라서 지정된다.
Young generation과 Old generation은 동시에 reclaim 된다.

 




 

 Serial

 Parallel

CMS 

G1 

병렬 수행

(Parallel)

X

 O

동시 수행(Concurrency)

X

 X

Young GC

Serial

Parallel 

Parallel 

 Parallel

Old Gc

 Serial

Parallel 

Parallel & Conc 

Parallel & Conc  



참조..

주요 정리 블로그

https://www.slipp.net/wiki/pages/viewpage.action?pageId=30770051

https://12bme.tistory.com/57

https://javabom.tistory.com/7?category=835783

https://johngrib.github.io/wiki/jvm-memory/

//g1gc 설명

https://imp51.tistory.com/entry/G1-GC-Garbage-First-Garbage-Collector-Tuning

//로그 분석 설명

https://b.luavis.kr/server/g1-gc

https://blog.naver.com/PostView.nhn?blogId=bumsukoh&logNo=110119881124&parentCategoryNo=&categoryNo=22&viewDate=&isShowPopularPosts=false&from=postView

// perm 과 메타스페이스 설명

https://mirinae312.github.io/develop/2018/06/04/jvm_memory.html


// java DNS TTL 관리

https://skysince.tistory.com/16

http://kwon37xi.egloos.com/4455415


// TLAB이란 무엇인가

https://m.blog.naver.com/PostView.nhn?blogId=kbh3983&logNo=220995694888&proxyReferer=https:%2F%2Fwww.google.com%2F