Garbage Collector

akanana·2021년 9월 27일
0

JavaPerformance

목록 보기
5/9
post-thumbnail

🏐Garbage Collcetor


사용하지 않는 Object 들을 제거하여 가용공간을 만들기 위한 기능
load variable section, operand stack, object reference 가 있을 시, reachable 이라 판단하여, 나머지들을 제거한다.

🏀GC Algorithm


🥎reference counting


detection 영역과 delete 영역이 나누어짐
매우 단순한 구조이며, reference count 가 0일때 gc를 수행한다.
순환참조의 문제로 memory leak 이 발생 할 가능성이 높다.

🥎Mark and Sweep


mark-phase 와 sweep phase 로 나누어짐
root set으로 부터 reference 관계인 object를 marking 한다.
sweep phase 에서는 marking 정보를 바탕으로 object 를 지우기 시작.
reference 관계가 정확하기에 순환참조 x 탐색범위또한 줄어든다.
단편화 문제가 발생하거나, STW 가 길다는 단점이 있다.

🥎Mark and Compacting


Sweep 단계를 Compacting 단계로 바꿈.
sweep 후 live object 들을 연속된 공간에 적재하여, 단편화를 방지시킨다.

🥎Copying


heap 을 active 와 inactive 영역 2가지로 나눈다.
active 영역이 가득 차 allocation 이 불가능 할 경우, gc를 실행, live object를 inactive 영역으로 copy.
단편화에는 유리 heap 영역을 절반만 쓸 수 있음.

🥎Generation


java8 쯔음 가장 효율적인 알고리즘으로, hotspot, ibm 모두 generation algorithm 을 채용하였다.
mark-sweep 과 copying 방식을 융합한 방식

🥎SATB(Snapshot at the Begeining)


write barrier 를 이용하여 reference 가 수정되기 전 내용을 linked list 에 저장.
concurrent 완료 후, stw 발생 => linked list 내용을 표시
satb-list 생성
애플리케이션 재개=>marking 단계. live object 들을 확인

🏀Hotspot JVM


oracle 사의 JVM 으로, 초기, Longview Technologies 의 JVM 이였으나, SUN 에 인수 후, oracle 사의 JVM 으로 편입되었다.

🥎Generation Collector


hotspot jvm 은 경험적으로 다음과 같은 사실을 알아내었다.

  1. object 는 allocation 된지 얼마 안 돼서 금방 garbage 가 된다.
  2. older 은 younger 을 참고하는 일이 드물다. card table 로 해결
  3. object 가 모인 곳은 단편화 확률이 높다

그러한 이유로 hotspot jvm은 generation algorithm 을 채택하였다.

card table?
old generation 을 대표하는 메모리 구조
younger object 를 참조하는 old object 에는 dirty card 에 체크를 한다.
minor gc 도중, dirty card 만 빠르게 검색하여 referenece 구조 파악 가능

🥎Hotspot Heap


generation 기반의 Heap 구조

  1. Eden 영역에 Allocation
  2. eden 영역이 가득 차면 minor GC 실행
  3. minor GC 에서 살아남은 Object들은 survivor0/1 영역을 오가며 age가 쌓인다.
  4. 특정 age에 도달한 Object들은 Old Generation 인 Tenured 영역으로 Promotion 한다.
  5. Tenured 영역이 가득 차면 major gc 를 실행한다.

Permanent vs Metaspace

java 7 이하의 버전에서는 permanent 영역이 존재하였다.
Class 메타데이터, Method 메타데이터, Static Object 변수, 상수 등을 저장하였다.
하지만 java 8 버전에 들어오면서 이 영역의 이름은 metaspace 로 바뀌었고, Heap 이 아닌 native 영역에서 이를 관리해주기 시작하며, OS가 크기를 동적으로 할당해주기 시작했다.
따라서 사용자는 Permanent 의 무거운 loading 시간을 겪지 않아도 되며, Permanent OOME 를 보지 않아도 된다.

java16 Buddy Allocation

Java 16 버전에서는 Metaspace 가 Buddy Allocation 기법을 통하여 설계되었다.

Buddy Allocation

메모리를 2^n 의 구조 (최소는 64k) 로 분할하여, 메모리를 구성한다.

  1. 메모리 요청시 적당한 크기의 메모리 슬롯을 찾는다
    1. 적당한 크기의 메모리 슬롯이 발견되면 프로그램에 할당
    2. 적당한 크기의 메모리 슬롯이 없을시, 메모리 슬롯을 만든다
      1. 요청된 메모리 크기보다 크게 메모리 슬롯을 절반으로 자름
      2. 하한선 까지 도착하면 (ex. 31k 프로그램일시 32k 까지 자름) 메모리를 할당
      3. 1번,적당한 크기의 메모리 슬롯 찾기로 돌아간다
      4. 메모리 슬롯을 찾을 때 까지 이 과정을 반복
  1. 메모리 블록 해제
  2. 주변 블록 탐색하여 해제된 상태인지 확인
    • (YES)두 메모리 블록을 조합, 다시 2번 단계로 돌아감.
    • (NO)단계 종료
Metaspace Issue

metaspace 사용시, class 를 대량으로 생성하는 경우 or 메모리 상한선을 정해버린 경우 OOM 이 발생 할 수 있다.
메모리가 적을때는 더 크게 할당해주면 끝날 문젱지만, 가끔 3rd party 에서 class 가 대량으로 발생하는 경우가 있다.
java + scala, java + kotlin 과 같은 application 에서 이와 같은 이슈가 발생하는 경우가 있다.
출처:에단박씨의브런치

🥎Hotspot GC


🥎Serial Collector


  • old-young 모두 serial 방식.
  • 최근에는 장비의 발달에 따라 대부분 사장되었다.

소규모 어플리케이션을 작동시킬때에는 여전히 효율적일 수 있다.
java 8 혹은 더 이전 환경에서, 소규모 장비에서 소규모 스레드와 소규모 데이터(대략 100mb 이하) 를 다루는 경우. 특히 단일 프로세서 환경에서 스레드간 오버헤드가 없기에, 적합할 수 있다.

🥎Parallel Collector


  • cpu 사용율을 극대화 시킴.
  • Collection 을 Parallel로 수행시킨다
  • corruption 발생 -> plap 을 사용하여 회피
    PLAP?

Serial 보다 조금 더 큰 규모에서 GC 시에 오버헤드를 크게 줄일 수 있다. 사실상 대부분의 환경에서 Default 로 돌아가는 Collector 이다.

🥎CMS Collector


java 1.4 ~ java 9(deprecated)~java14(remove)

  • Concurrent Mark Sweep
  • Heap 메모리가 클때 유리한 방식이다.
  • Mark-and-Sweep 방식을 이용
  • Suspend 를 분산하여 응답시간을 개선

병렬(concurrent) 방식을 사용하기 때문에, 중단 시간을 최소화 시킬 수 있다. 전체 처리량보다 응답시간이 더 중요 할 수 있는 어플리케이션일시, 상당히 유리하다. JAVA 8 혹은 그 이하 버전에서 상당히 유리하다.

🥎G1 Collector


java 7 ~ java9(default) ~

  • java 7 부터 등장했으며, 9버전부터 default 가 된 GC 이다
  • 4GB 가량의 Heap 에서도 매우 빠른 속도로 동작한다
  • generation heap 이 아닌, region 을 바탕으로 한 heap 을 사용한다.
  • heap 을 2048 개의 region 으로 나누어 이용.
  1. Young GC
    • minor GC 와 동일한 개념
    • live object 를 survivor, old region 으로 copy
  2. Concurrent Mark Phase
    1. Mark
      • single thread 로 작동
      • concurrent 로 실행
      • initial mark 수행
    2. Remark
      • STW 발생
      • reachable object 들을 탐색
      • garbage region 을 삭제시킴
  3. Old Region Reclaim Phase
    1. Remark
      • concurrent 로 실행
      • live object 비율이 낮은 region을 mark
    2. Evacuation Pause
      • young gc 도 함께 수행
      • survivor region, old region 을 생성, mark 된 곳의 region을 copy 시킨다
  4. compaction phase
    • concurrent 로 실행
    • region 단위로 작동
    • free space 를 병합. 단편화를 방지한다.

CMS 를 대체하고자 나온 Collector 로, suspend 시간이 cms에 비해 예측 가능하며, 일시중지 대상또한 지정 가능하다. 기존 heap 과는 구조가 상당히 상이하지만, 여전히 논리적으로는 generation heap 이라고 할 수 있다. SATB 를 통해 모든 live object 가 탐색됨을 보장한다.

🥎ZGC


java11 ~
11버전에 출시 후, 15버전에 정식으로 나왔다.
64bit에서만 사용 가능하며, 11버전 밑으로는 호환도 되지 않는다.
heap 이 큰 경우에 엄청 유리하며, 극단적으로 16TB 환경에서도 돌아간다.
Colored Pointer 와 Load Barrier 가 핵심 기술이다.

Object Layout

기존의 java header?
위 링크에 잘 정리되어있다. java 의 Lock 상태에 대해 알면 더 좋은 글이다.
age는 4bits 이며, java 5버전까지는 5bits, 그 후에는 4bits 로 바뀌었다. 그에따라 MaxTenuringThreshold 는 31 에서 15로 바뀌었다.

Colored Pointers


zgc의 java header
Finalizable : finalizer 을 통해 참조되는 object 의 garbage
Remapped : 재배치 여부를 판단하는 mark
marker1/0: Live Object 를 판단하는 bit

Load Barriers


메모리 재배치시 STW 없이 재배치.

  1. Remapped 비트가 1이면 최신상태. 1이면 재배치 x
  2. 개체가 relocate set 에 위치했는지 확인. 아닐시 재배치 x
  3. 재배치 대상임을 확인. 재배치 됐는지 확인.
    • yes: 다음 단계
    • no: 재배치 + 포워딩 테이블에 항목을 추가
  4. 새 위치로 업데이트 후, 리맵 비트를 설정.
42bits 면 4TB 인데요?


그림과 같은 방식으로 colored bit 를 통해 16TB 까지 지원

🥎Shenandoah


java12 ~
RedHat 에서 개발한 Collector

copy 로 인한 puase 가 삭제. 결국 전체적으로 STW 를 줄이는 방향으로 발전하였다.
RedHat 개발자 Christine FLood 도 그러했고, Oracle 의 ZGC 개발도 그러했고, 더이상 Young Object 가 죽을 가능성이 크다고 보지는 않는 느낌이다. 결국 이는 Generation Algorithm 의 탈피로 이어지고 있다.

0개의 댓글