일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Spring/JAVA 서적
- Be
- TDD
- Self Descript Message
- testdrivendevelopment
- Solid
- ComponentScan
- Runtime Area
- 자식객체
- pair programming
- 완벽이해
- ATDD
- GC
- 트랜잭션 격리 수준
- Java 22
- 부모객체
- 마이크로서비스디자인패턴
- hateoas
- M:N
- Execution Engine
- 스프링으로하는마이크로서비스구축
- 미니미프로젝트
- docker
- java
- KPT
- G1GC
- 도커
- RESAPI
- DB
- 클린코드
- Today
- Total
Programming Summary
Java) GC란? 본문
1) GC란 무엇일까?
GC의 정의
자바의 언어적인 특성은 어떤게 있을까? 객체 지향, JVM, 그리고 GC가 보통 많이 언급된다. GC(Garbage Collector)는 메모리 관리 기법 중의 하나로, 프로그램이 동적으로 할당했던 메모리의 힙 영역 중에서 필요없게 된 영역을 해제하는 기능이다. GC를 통해 통해 프로그래머는 동적으로 할당한 메모리 영역 전체를 완벽하게 관리하지 않아도 되며, 메모리 누수나 유효하지 않은 포인터 접근에 대한 문제점을 막을 수 있다.
이러한 GC를 사용하는 언어로 자바, Python, Perl 등을 예시로 들 수 있다.
힙 영역의 구성
위 그림은 JDK 1.8이후 힙 메모리 구조이다. 크게 Young Generation과 Old Generation, 그리고 Meta Space로 나눌 수 있다. Meta Space에는 클래스와 메소드의 meta 정보들이 저장되고 Young Generation과 Old Generation에 실질적인 객체들이 저장된다.
용어 정리
Mark
- 접근 가능한 객체에 특정 표시를 하는 행위
Sweep
- Mark 되지 않은 객체를 제거하는 과정
Compact
- sweep 후 발생한 메모리 단편화를 없애는 과정
Promotion
- Survivor 영역에서 계속해서 살아남은 객체들이 특정 age에 도달하면 Old Generation으로 이동하는 과정
Summary
- 흰색 : Reachable Object, 회색 : Unreachable Object
- Region 별로 살아있는 객체의 밀도를 판단하여 객체의 밀도가 높다고 판단되는 부분까지 Dense prefix를 지정함. Mark-Summary-Compact 과정에서 dense prefix를 기준으로 Sweep-Compaction을 진행하여 Compaction 범위를 줄임.
2) GC 동작 방식
GC 대전제
- 대부분의 객체는 쉽게 Garbage가 된다.
- Old generation 영역의 객체가 Young Generation의 객체를 참조하는 일은 드물다.
GC 동작 방식
GC 종류
기본적으로 GC는 크게 Minor GC와 Major GC로 나뉜다. Minor GC의 경우 Young Generation 영역에 대해 GC를 실행하는 것을 의미하며, Major GC에 비해 더 빠르고 자주 실행된다. Major GC는 Old Generation 영역을 대상으로 GC를 실행하는 것을 의미하며 Minor GC에 비해 10배 이상의 시간이 소모될 수도 있다.
객체가 기본적으로 생성이 되면 Eden 영역에 저장이 되게 된다. Eden 영역이 전부 차게 된다면, Minor GC가 Young Generation을 기준으로 실행이 되며, 이때 살아남은 객체들은 Survivor Area로 이동이 된다. 그리고 살아남은 횟수인 age 값이 증가하게 된다.
Survivor 영역은 최소 1번 이상의 GC 이후 남은 객체가 존재하는 영역으로 이 영역 역시 Minor GC의 대상이 된다. Survivor 영역은 Survivor-0, Survivor-1로 구성되어 있다. 그리고 Minor GC 때 서바이버 영역에서 살아남은 객체들과 eden에서 남은 객체들을 반대 Survivor 영역으로 이동하게 된다.(그렇기에 한 survivor 영역은 항상 비어있다) 그렇게 Survivor 영역의 객체들의 object header에 일정 횟수 이상의 age가 쌓이면 살아남은 객체들을 Old Generation 영역으로 이동시킨다. 그리고 Old Generation 영역까지 전부 차게 되면 Old Generation 영역을 대상으로 하는 Major GC가 발생하게 된다.
이 두 과정을 합쳐 Full GC라 일컫는다.
GC 동작 방식
Stop the World와 Mark-And-Sweep 과정으로 이루어진다.
Stop the World란 가비지 컬렉션 실행을 위해 JVM이 애플리케이션의 실행을 잠시 멈추는 작업을 말한다. 이때 GC를 실행하는 스레드 외의 모든 스레드의 작업이 중단되고, GC 작업이 완료되면 작업이 재개되게 된다. Mark-and-Sweep이란 GC가 객체들을 식별하고 제거하는 과정으로 이를 3단계로 나눠보면 다음과 같다.
- Heap 영역에 존재하는 객체들에 대해 접근 가능한지를 확인한다.
- 이때 접근이 가능하다면 Reachable Object, 접근이 불가능하다면 Unreachable Object라고 부른다.
- GC Root에서부터 시작하여 참조값을 따라가며 접근 가능한 객체들에 Mark하는 과정을 진행한다.
- GC의 Root는 stack 영역에 존재하는 참조 변수 혹은 static 데이터, JNI에 의해 생성된 객체들이 될 수 있다.
- Mark되지 않은 객체 즉, 접근할 수 없는 객체는 제거(Sweep) 대상이 되고, 해당 객체들을 제거한다.
정리하자면, 가비지 컬렉션이 될 대상 객체를 식별(Mark)하고 제거(Sweep)한 후, 파편화된 메모리 영역을 앞에서부터 채워가는 작업(Compaction)을 수행하게 된다.
3) GC의 종류
기본적으로 GC는 Stop The World 시간을 단축시키는 것이 목표로 발전했다.
Serial GC
제일 단순한 방식의 GC로 싱글 스레드로 동작한다. 그만큼 느리고 Stop The World 시간이 다른 GC에 비해 길며, 실무에서 사용하는 경우는 거의 없다.
- Mark & Sweep & Compact 알고리즘 사용
Parallel GC
Java 8의 default GC로 멀티 스레드 방식을 사용하기 때문에, Serial GC에 비해 상대적으로 Stop The World가 짧다. Old Parallel GC는 일반 parallel GC와 비교해서 Old 영역을 처리하는 방법이 다르다.
- Mark & Sweep & Compact 알고리즘 사용.
- Old parallel GC : Old 영역 한정 Mark & Summary & Compact 알고리즘 사용
CMS(Concurrent Mark Sweep) GC
CMS GC는 GC의 과정을 4단계로 분할하고 애플리케이션과 동시적으로 동작할 수 있는 과정은 동시에 실행하여 Stop The World 시간을 더 단축 시킨 GC이다.
- Initial Mark : GC Root가 참조하는 객체만 마킹(Stop the World 발생)
- Concurrent Mark : 참조하는 객체를 따라가며 지속적으로 마킹
- Remark : Concurrent Mark 과정에서 변경된 사항이 없는지 재 확인 하는 과정(Stop the World 발생)
- Concurrent Sweep : 접근할 수 없는 객체를 제거하는 과정
이러한 CMS GC는 G1 GC의 등장과 너무 많은 인수로 인한 GC 복잡도 증가로 인해 Java 9부터 Deprecated 되었다.
G1 GC
G1은 Garbage First의 약어로 Garbage만 있는 Region을 먼저 회수한다고 해서 붙여진 이름이다. 자바 9+의 default GC이며, CMS GC를 개선하여 만든 GC로 Heap 영역을 Region 단위로 분리하였다. Region이란 일정한 크기(default : (전체 Heap 메모리) / 2048)를 갖는 영역으로 전체 Heap에 대해서 탐색하지 않고 부분적으로 Region 단위로 탐색을 진행하게 하여 Stop The World 시간을 줄였다. 각 영역들은 Eden, Survivor, Old, Unused, Humongous 등이 될 수 있다.
최근 Java 22버전 릴리즈로 Region Pinning 기술이 적용 되어 GCLocker 없이도 G1 GC가 가능해졌다. 이를 통해 GC 진행 중에도 JNI가 공유 자원에 접근이 가능해져 성능 향상이 이루어졌다.
G1 GC는 위 그림처럼 Young-only Phase와 Space Reclamation Phase를 반복한다. 사이클의 원은 STW가 발생한 것을 나태내고 원의 크기에 따라 STW 소요 시간이 달라진다.
파란 원은 Minor GC가 진행함에 따라 STW가 발생한 것이고, 주황 원은 Major GC가 진행되면서 객체를 마킹 및 기타 과정을 하기 위해 STW가 발생된 것. 빨간 원은 Mixed GC를 진행함에 따라 STW가 발생한 것이다.
Young-only Phase는 Minor GC만 수행하다가 정해놓은 Old Generation의 비율이 설정해놓은 초기 힙 비율을 초과하는 순간, Major GC가 수행된다. Major GC의 첫 단계는 Initial Mark이며 Minor GC, Concurrent Mark가 동시에 수행되는데 Remark가 수행되는 순간 다른 작업은 멈추게 된다.(Major GC 동작 과정은 CMS와 같다)
Space Reclamation(공간 회수) Phase에서는 Mixed GC가 수행되는데 Mark 단계가 없어서 STW 빈도가 Young Only Phase에 비해 줄어든 것을 볼 수 있다.
Epsilon GC(No-Op GC)
Java11버전에서 ZGC와 함께 추가되었다. Epsilon GC는 제한된 할당 한도와 최대한 낮은 오버헤드 레이턴시를 구현한 GC이다. 쉽게 말하면 메모리 할당만 하고 GC로서의 역할을 거의 하지 않는다(No-Op GC). 또한 타 GC들과 다르게 Heap 영역이 가득차면 OS에게 추가 Heap 영역을 할당 받지 않고 JVM을 종료한다. 그렇기에 이 GC는 실사용목적보다는 성능 테스트나 메모리 압력 테스트와 같은 특수한 목적을 위해 사용된다.
Z GC
ZGC는 조금 더 큰 메모리(8MB~16TB)에서 효율적인 GC이다. ZGC는 Z Page를 활용하여 GC를 진행하게 된다. ZGC는 STW 시간(무려 10ms 이내가 보장된다고 한다..!) 을 최대한 적게 가져가기 위해 제작되었다. ZGC는 Colored pointers와 Load barriers라는 주요한 2가지 알고리즘이 존재한다. 사실 너무 어려워서 어떤 식으로 동작하는지 파악하지 못했다.. 이에 대해서는 하단의 참조 링크를 참조하기 바란다.
참고
'CS 공부' 카테고리의 다른 글
Java) G1 GC를 어떻게 뜯어볼까? (6) | 2024.04.16 |
---|---|
Infra) 인터넷경계 로드밸런서(Load Balancer)는 어디에 위치할까? (2) | 2024.04.09 |
DB) 트랜잭션 격리수준이란? (1) | 2023.09.22 |
DB) MVCC(Multi Version Concurrency Control)란? (0) | 2023.09.22 |
DB) 인덱스란? (1) | 2023.09.21 |