-
[Java] Hotspot JVM Garbage Collection 과정Programming/Java 2021. 8. 23. 21:22
Garbage Collection(GC)은 메모리 관리 기법 중 하나로, 프로그램이 동적으로 할당한 메모리 영역 중 더 이상 사용하지 않는(않을 것이라 판단되는) 영역을 해제하는 기법이다.
C언어의 malloc을 이용한 동적 할당은 free를 통해 사용자가 메모리 해제의 시점과 여부를 선택해야 했다.
//SIZE 만큼 동적할당 int* arr = (*int)malloc(sizeof(int)*SIZE); //직접 메모리 영역 해제 free(arr);
이러한 방식은 해제해야 할 메모리 영역도 그대로 남아있는 메모리 누수를 발생시킬 수 있기 때문에 요즘의 언어에서는 메모리가 더 이상 참조되지 않는 시점에 알아서 메모리를 해제하는 GC를 두는 것이 일반적이다.
이 글에서는 JVM(Java Virtual Machine)에서 Garbage Collection이 동작하는 지에 대해 알아본다.
JVM(Java Virtual Machine): Java 바이트 코드를 해석하고 실행하는 주체. CPU, 운영 체제의 종류와 무관하게 플랫폼 독립적으로 자바 바이트코드가 실행되도록 보장한다.
Garbage Collection의 대상
👉 Stack의 모든 변수 & Reachable Object가 참조중인 객체(Mark)를 제외한 Heap에 남아있는 객체가 GC(Sweep)의 대상이 된다
자바에서는 프로그램 코드를 통해 메모리를 명시적으로 해제하지 않고, 가비지 컬렉터가 필요 없는 객체를 찾아 지우는 작업을 한다.
HotSpot VM에서는 다음의 두 가지 조건을 포함하는 'weak generational hypothesis' 가설에 따라 물리적 공간을 크게 두 개로 나누었다.
- 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다
- 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다
Young Generation: 새롭게 생성한 객체의 대부분이 위치하는 곳. 대부분의 객체는 금방 접근 Unreachable 상태가 되기 때문에 대다수의 객체가 Young 영역에 생성되었다가 사라진다(Minor GC).
Old Generation: Unreachable 상태가 되지 않아 Young 영역에서 살아남은 객체가 복사되는 곳. 대부분 Young 영역보다 크게 할당하며, 그에 비해 GC는 적게 발생함(Major/Full GC).
Young 영역에 대한 Garbage Collection
- 새로 생성한 대부분의 객체는 Eden 영역에 위치
- Eden 영역에서 GC가 한번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동
- Eden 영역에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역으로 객체가 계속 쌓임
- 하나의 Survivor 영역이 가득 차게 되면 그 중 살아남은 객체를 다른 Survivor 영역으로 이동한 뒤 기존 Survivor 영역은 비움
- 위의 과정을 반복하다가 Age가 커진 객체는 Old 영역으로 이동한다
GC의 대상이 되는 영역이 이동함을 쉽게 알아볼 수 있는 그림들을 가져왔다
Old 영역에 대한 Garbage Collection
Old 영역은 기본적으로 데이터가 가득 찰 시 GC를 실행한다
- Serial GC
- mark-sweep-compact 알고리즘 사용
- 살아 있는 객체를 식별(Mark)한다
- heap의 앞 부분부터 확인하여 살아 있는 객체만 남긴다(Sweep)
- 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워서 객체가 존재하는 부분/없는 부분으로 나눈다(Compaction)
- 운영 서버에서는 절대 사용하면 안됨(CPU 코어가 하나일 때 적용하려고 고안된 방식)
- Parallel GC
- Serial GC와 비교하여 기본 알고리즘은 동일
- GC를 처리하는 쓰레드가 여러 개
- 메모리가 충분하고 코어 개수가 많을 때 유리
- Parallel Old GC(Parallel Compacting GC)
- Parallel GC와 동일하지만 Old 영역의 GC 알고리즘만 다름 (Mark-Summary-Compaction)
- Summary 단계에서 앞서 GC를 수행한 영역에 대해 별도로 살아 있는 객체를 식별
- Concurrent Mark & Sweep GC(CMS)
- Initial Mark: 클래스 로더에서 가장 가까운 객체 중 살아 있는 객체 마크(멈추는 시간 매우 짧음)
- Concurrent Mark: 이전에 살아있다고 확인한 객체에서 참조하는 객체들을 따라가면서 확인(다른 스레드가 실행 중인 상태에서 동시 진행)
- Remark: 이전 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인
- Concurrent Sweep: 쓰레기를 정리
- 특징
- 장점: stop-the-world 시간이 매우 짧아서 응답 속도가 매우 중요할 시 사용
- 단점: 다른 GC 방식보다 메모리 및 CPU 많이 소모, Compaction 단계 제공 X, Compaction 작업 실행 시 다른 알고리즘보다 stop-the-world 시간이 더 길 수 있음
- G1(Garbage First) GC
- 바둑판의 각 영역에 객체를 할당하고 GC 실행
- 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 GC 실행 (Young의 세 가지 영역 -> Old 영역으로 이동하는 단계가 사라진 GC)
- 위의 모든 GC 알고리즘보다 빠름
- JDK 7에서 정식으로 포함하여 제공
더보기➕ plus
GC를 실행하게 되면 'stop-the-world'(GC을 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것. GC을 실행하는 Thread를 제외한 나머지 Thread는 모두 작업을 멈추고, GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작)가 발생한다.
대부분의 경우에 GC튜닝이란 stop-the-world 시간을 줄이는 것을 말한다.
참고자료
- https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
- https://d2.naver.com/helloworld/1329'Programming > Java' 카테고리의 다른 글
String Pool - Java의 String은 어디에 저장될까 (433) 2021.08.26 Checked and Unchecked Exception (422) 2021.08.25 [Java] Primitive Data Types (336) 2021.08.22 [Java] Abstract Class(추상 클래스)와 Interface(인터페이스)의 차이 (277) 2021.08.15 [Java] String 🆚 StringBuffer 🆚 StringBuilder 무슨 차이일까? (0) 2021.07.23