사용하지 않는 Object 들을 제거하여 가용공간을 만들기 위한 기능
load variable section, operand stack, object reference 가 있을 시, reachable 이라 판단하여, 나머지들을 제거한다.
detection 영역과 delete 영역이 나누어짐
매우 단순한 구조이며, reference count 가 0일때 gc를 수행한다.
순환참조의 문제로 memory leak 이 발생 할 가능성이 높다.
mark-phase 와 sweep phase 로 나누어짐
root set으로 부터 reference 관계인 object를 marking 한다.
sweep phase 에서는 marking 정보를 바탕으로 object 를 지우기 시작.
reference 관계가 정확하기에 순환참조 x 탐색범위또한 줄어든다.
단편화 문제가 발생하거나, STW 가 길다는 단점이 있다.
Sweep 단계를 Compacting 단계로 바꿈.
sweep 후 live object 들을 연속된 공간에 적재하여, 단편화를 방지시킨다.
heap 을 active 와 inactive 영역 2가지로 나눈다.
active 영역이 가득 차 allocation 이 불가능 할 경우, gc를 실행, live object를 inactive 영역으로 copy.
단편화에는 유리 heap 영역을 절반만 쓸 수 있음.
java8 쯔음 가장 효율적인 알고리즘으로, hotspot, ibm 모두 generation algorithm 을 채용하였다.
mark-sweep 과 copying 방식을 융합한 방식
write barrier 를 이용하여 reference 가 수정되기 전 내용을 linked list 에 저장.
concurrent 완료 후, stw 발생 => linked list 내용을 표시
satb-list 생성
애플리케이션 재개=>marking 단계. live object 들을 확인
oracle 사의 JVM 으로, 초기, Longview Technologies 의 JVM 이였으나, SUN 에 인수 후, oracle 사의 JVM 으로 편입되었다.
hotspot jvm 은 경험적으로 다음과 같은 사실을 알아내었다.
그러한 이유로 hotspot jvm은 generation algorithm 을 채택하였다.
card table?
old generation 을 대표하는 메모리 구조
younger object 를 참조하는 old object 에는 dirty card 에 체크를 한다.
minor gc 도중, dirty card 만 빠르게 검색하여 referenece 구조 파악 가능
generation 기반의 Heap 구조
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) 로 분할하여, 메모리를 구성한다.
- 메모리 요청시 적당한 크기의 메모리 슬롯을 찾는다
- 적당한 크기의 메모리 슬롯이 발견되면 프로그램에 할당
- 적당한 크기의 메모리 슬롯이 없을시, 메모리 슬롯을 만든다
- 요청된 메모리 크기보다 크게 메모리 슬롯을 절반으로 자름
- 하한선 까지 도착하면 (ex. 31k 프로그램일시 32k 까지 자름) 메모리를 할당
- 1번,적당한 크기의 메모리 슬롯 찾기로 돌아간다
- 메모리 슬롯을 찾을 때 까지 이 과정을 반복
- 메모리 블록 해제
- 주변 블록 탐색하여 해제된 상태인지 확인
- (YES)두 메모리 블록을 조합, 다시 2번 단계로 돌아감.
- (NO)단계 종료
Metaspace Issue
metaspace 사용시, class 를 대량으로 생성하는 경우 or 메모리 상한선을 정해버린 경우 OOM 이 발생 할 수 있다.
메모리가 적을때는 더 크게 할당해주면 끝날 문젱지만, 가끔 3rd party 에서 class 가 대량으로 발생하는 경우가 있다.
java + scala, java + kotlin 과 같은 application 에서 이와 같은 이슈가 발생하는 경우가 있다.
출처:에단박씨의브런치
소규모 어플리케이션을 작동시킬때에는 여전히 효율적일 수 있다.
java 8 혹은 더 이전 환경에서, 소규모 장비에서 소규모 스레드와 소규모 데이터(대략 100mb 이하) 를 다루는 경우. 특히 단일 프로세서 환경에서 스레드간 오버헤드가 없기에, 적합할 수 있다.
PLAP?
Serial 보다 조금 더 큰 규모에서 GC 시에 오버헤드를 크게 줄일 수 있다. 사실상 대부분의 환경에서 Default 로 돌아가는 Collector 이다.
java 1.4 ~ java 9(deprecated)~java14(remove)
병렬(concurrent) 방식을 사용하기 때문에, 중단 시간을 최소화 시킬 수 있다. 전체 처리량보다 응답시간이 더 중요 할 수 있는 어플리케이션일시, 상당히 유리하다. JAVA 8 혹은 그 이하 버전에서 상당히 유리하다.
java 7 ~ java9(default) ~
CMS 를 대체하고자 나온 Collector 로, suspend 시간이 cms에 비해 예측 가능하며, 일시중지 대상또한 지정 가능하다. 기존 heap 과는 구조가 상당히 상이하지만, 여전히 논리적으로는 generation heap 이라고 할 수 있다. SATB 를 통해 모든 live object 가 탐색됨을 보장한다.
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 없이 재배치.
- Remapped 비트가 1이면 최신상태. 1이면 재배치 x
- 개체가 relocate set 에 위치했는지 확인. 아닐시 재배치 x
- 재배치 대상임을 확인. 재배치 됐는지 확인.
- yes: 다음 단계
- no: 재배치 + 포워딩 테이블에 항목을 추가
- 새 위치로 업데이트 후, 리맵 비트를 설정.
42bits 면 4TB 인데요?
java12 ~
RedHat 에서 개발한 Collector
copy 로 인한 puase 가 삭제. 결국 전체적으로 STW 를 줄이는 방향으로 발전하였다.
RedHat 개발자 Christine FLood 도 그러했고, Oracle 의 ZGC 개발도 그러했고, 더이상 Young Object 가 죽을 가능성이 크다고 보지는 않는 느낌이다. 결국 이는 Generation Algorithm 의 탈피로 이어지고 있다.