JAVA Garbage Collection
프로그래밍2020. 6. 14. 17:49
편집기랑 게시글이랑 출력 내용이 다르네요...편집기에서는 들여쓰기랑 영역 구분 다 해뒀는데...ㅠㅠ
- Young 영역(Yong Generation 영역): 새롭게 생성한 객체의 대부분이 여기에 위치한다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라진다. 이 영역에서 객체가 사라질때 Minor GC가 발생한다고 말한다.
- Old 영역(Old Generation 영역): 접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 여기로 복사된다. 대부분 Young 영역보다 크게 할당하며, 크기가 큰 만큼 Young 영역보다 GC는 적게 발생한다. 이 영역에서 객체가 사라질 때 Major GC(혹은 Full GC)가 발생한다고 말한다.
- Method 영역 : 객체나 억류(intern)된 문자열 정보를 저장하는 곳이며, Old 영역에서 살아남은 객체가 영원히 남아 있는 곳은 절대 아니다. 이 영역에서 GC가 발생할 수도 있는데, 여기서 GC가 발생해도 Major GC의 횟수에 포함된다.
- "Old 영역에 있는 객체가 Young 영역의 객체를 참조하는 경우가 있을 때에는 어떻게 처리될까?"라고 궁금해 하는 분도 더러 있을 것이다. 이러한 경우를 처리하기 위해서 Old 영역에는 512바이트의 덩어리(chunk)로 되어 있는 카드 테이블(card table)이 존재한다.
- 카드 테이블에는 Old 영역에 있는 객체가 Young 영역의 객체를 참조할 때마다 정보가 표시된다. Young 영역의 GC를 실행할 때에는 Old 영역에 있는 모든 객체의 참조를 확인하지 않고, 이 카드 테이블만 뒤져서 GC 대상인지 식별
[Young 영역]
크게 Eden 영역과 Survivor 영역으로 나뉘는데, Survivor 영역은 2개이다. 신규 객체는 Eden 영역에 위치하게 되고 GC가 발생한 후 남은 객체는 Survivor 영역으로 이동한다. 이 때, Survivor 영역은 둘 중 하나만 사용하며, 사용하는 영역이 가득 찰 경우 GC가 발생, 남은 객체들을 다른 Survivor 영역으로 이동시킨다. 이 과정을 반복하면서 살아남은 객체는 Old 영역으로 이동시킨다.
[Old 영역]
데이터가 가득 차면 GC를 실행한다…
[GC 방식]
- Serial GC
- 메모리가 작고 CPU 코어 개수가 적을 때 적합한 방식으로, 고성능 시스템 서비스 단계에서 사용할 경우, 충분히 고민해보고 적용해야하는 방법이다. Mark-Sweep-Compact 알고리즘을 사용하여 GC를 수행한다.(살아있는 객체를 식별 – 힙의 앞 부분부터 확인하여 살아있는 것만 남김 – 힙의 앞 부분부터 채워서 객체가 존재하는 부분과 없는 부분으로 나눈다)
Young Generation에서는 memory compaction을 수행하지 않아 시간 상의 이점을 가지며, Old Generation은 memory compaction도 하고, 영역 사이즈가 크다보니 수행 시간이 길다.
- 메모리가 작고 CPU 코어 개수가 적을 때 적합한 방식으로, 고성능 시스템 서비스 단계에서 사용할 경우, 충분히 고민해보고 적용해야하는 방법이다. Mark-Sweep-Compact 알고리즘을 사용하여 GC를 수행한다.(살아있는 객체를 식별 – 힙의 앞 부분부터 확인하여 살아있는 것만 남김 – 힙의 앞 부분부터 채워서 객체가 존재하는 부분과 없는 부분으로 나눈다)
- Parallel GC
- Serial GC와 기본적인 알고리즘은 같으며, 멀티 프로세스 또는 멀티 스레드 환경에서 빠르게 처리하기 위한 방법이다.
- Tri-Color Marking Algorithm
- 회색(Grey) : 해당 객체가 참조하고 있는 객체를 식별하지 않은, 즉 처리가 되지 않은 객체
- 흰색(White) : 해당 객체를 참조하고 있는 객체가 아무런 객체도 없는 객체, 수집 대상이 되는 객체
- 검은색(Black) : 해당 객체가 참조하고 있는 객체를 모두 식별한, 즉 모든 처리를 끝마친 객체
- 아직 참조 데이터를 탐색하지 않은 상태인 회색 마킹이 된 객체에서 탐색을 진행하며, 참조하고 있는 객체를 회색으로 마킹한 후 자신을 검은색으로 마킹하여 처리를 끝냈다는 상태로 표시한다. 이 과정을 반복해서 참조되지 않고 있는 흰색 마킹이 된 객체들에 대해서 수집이 발생하게 된다.
- Tri-Color Marking Algorithm의 경우 Mark and Sweep Algorithm와 달리, 어플리케이션과 동시에 수행된다. GC시점과 객체 생성 및 참조 시점의 타이밍 이슈가 발생할 수 있는 가능성이 있다.
- CMS(Concurrent Mark Sweep) GC
- Tri-color Marking Algorithm을 사용하기 때문에 GC와 함께 어플리케이션을 돌릴 수 있다. 그렇다고 해서 아예 STW가 없는 건 아닌데 짧은 시간 내에 이뤄진다. 어플리케이션의 응답 속도가 매우 중요할 때 CMS GC를 사용하며, Low Latency GC라고도 부른다. 다른 GC보다 메모리와 CPU를 더 많이 사용하며 Compaction을 기본적으로 제공되지 않는다. 그래서 조각난 메모리가 많아 Compaction 작업을 실행하면 다른 GC방식의 STW보다 시간이 더 길어질 수 있다.
- Initial Mark 단계에서 STW가 발생하며 클래스 로더에서 가장 가까운 객체 중 살아 있는 객체만 찾는 것으로 끝낸다. 그렇기 때문에 멈추는 시간이 짧다.
- Concurrent Mark 단계에서는 방금 살아있다고 확인한 객체에서 참조하고 있는 객체들을 따라가면서 확인한다. 다른 스레드가 실행 중인 상태에서 동시에 진행된다
- Remark 단계에서도 STW가 발생하며 Concurrent Mark 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인한다.
- Concurrent Sweep 단계에서는 쓰레기를 정리하는 작업을 실행한다. 이 작업도 다른 스레드가 실행되고 있는 상황에서 진행한다.
- G1 GC
- 거대 영영이라는 특수 영역이 존재하며 무게가 꽤 나가는(?) 객체는 바로 Old Generation에 할당한다. 말도 많고 탈도 많은 CMS GC를 대체하기 위해서 만들어 졌다. JDK 6에서는 G1 GC를 early access라고 부르며 그냥 시험삼아 사용할 수만 있도록 한다. 그리고 JDK 7에서 정식으로 G1 GC를 포함하여 제공했으며, JDK 9부터 기본 GC로 채택됐다.
- G1 GC는 힙을 ‘영역(Region)’이라는 것으로 구성한다.(힙의 크기가 4GB일 때, 영역의 크기 = 힙크기(4096) / 2048 = 2(MB)
- 영역 중에 모든 객체가 죽은 영역(유효한 객체가 없는 영역, 즉 Garbage만 있는 Region)부터 회수를 한다. 빠른 메모리 회수를 통해 하면 빈 공간 먼저 확보하는 것.
- 전체 힙에 대해 GC를 수행하지 않고 Region별로 GC를 수행하며 Compaction 또한 Region별로 수행한다. 또한 Remembered Set으로 힙 영역 참조 레퍼런스를 관리하기 때문에 대용량 힙에서도 낮은 중단 시간을 가질 수 있게 됐다.
- Minor GC 이후에 Survivor Space로 객체를 옮기거나 Old Generation으로 객체를 옮겨야한다. 이 때 G1 GC는 해당 객체를 기존의 Region 혹은 새 Region에 복사후에 메모리를 compact시킨다. Major GC 시에도 마찬가지로 Old Generation Region에 있는 생존 객체를 다른 리전으로 이동시킨 후 해당 메모리를 Compact한다. 하지만 Old Generation의 특수한 리전인 Humongous Region에 대해서는 Evacuation이 발생하지 않는다. 그냥 해당 리전의 객체(Humongous Object)가 더 이상 참조하는 객체가 없어서 사망하셨으면 바로 회수해간다.
'프로그래밍' 카테고리의 다른 글
VisualStudioCode C++ 디버깅 오류 (0) | 2021.09.25 |
---|---|
[WINAPI] GetDriveType 함수 (0) | 2016.08.31 |