-
[JAVA/Garbage Collection] 가비지 컬렉션에 관하여Mhwan's Study/JAVA & Kotlin 2021. 1. 21. 00:38
자바는 다른 언어와 달리 개발자가 직접 객체를 메모리에서 해제하지 않아도 됩니다. 바로 Garbage Collector가 있기 때문인데, GC는 힙 메모리 영역에 존재하는 객체를 메모리에서 삭제하는 역할을 합니다.
# GC의 대상
1. 객체가 Null인 경우
2. 블럭 실행 종료 후, 블럭 안에서 생성된 객체
3. Null인 부모객체를 포함하는 자식 객체
현재 사용하지 않는 객체를 힙에서 지우는 것으로 가비지 컬렉션의 과정을 Mark And Sweep이라고 합니다.
- Mark : JVM의 가비지 컬렉터가 스택에서 참조하고 있는 힙에 있는 영역을 모두 마킹합니다. 이 마킹 작업을 위해 현재 작업중인 모든 스레드를 중단(stop the world)하며, 이 때문에 System.gc()를 함부로 호출하면 안됩니다.
- Sweep : 위에 Mark작업에서 마킹되지 않은 오브젝트를 힙에서 지우는 것으로 이것은 빠르게 할 수 있습니다.
이 때문에 GC의 성능은 Mark과정에서 어떤 GC알고리즘을 사용해 시간을 줄일지에 좌우 됩니다.
# Minor GC & Major GC
우선 힙의 영역은 크게 Young, Old로 나뉩니다.
- Young영역은 새롭게 생성하는 객첵가 존재하며, 객체의 대부분이 여기서 금방 접근 불가능 상태가 됩니다. (Minor GC).
- Old영역은 Young 영역에서 오래동안 살아 남은 것이 존재하며, Young 영역보다 크기도 크고, GC는 적게 일어납니다. (Major GC)참고로 Metaspace 부분은 자바 8부터 새롭게 생긴 영역으로 자바 7버전 까지는 permanent Gen이라는 이름으로 클래스의 메타데이터나 문자열 정보를 저장하는 영역으로 존재했었습니다.
Minor GC (Young 영역에서 GC)과정
1. 새로운 객체가 생성되면 Eden영역에 할당되며, S0, S1(Survival 0, Survival 1)은 비워진 상태입니다
2. Eden영역이 가득차면 Minor GC가 발생하고 여기서 살아남은 객체(Reachable 오브젝트)는 S0영역중 하나로 이동합니다
3. 위의 1~2과정으로 다음 Minor GC가 발생하면서 살아 남는 객체는 계속 S0 영역으로 객체가 쌓입니다.
4. 하나의 S0 영역이 가득차고, 이때에도 Reachable 오브젝트들은 또 다른 S1 영역으로 이동하고 age가 증가합니다. (age는 survivor 영역에서 또 다른 survivor영역으로 이동할 때 증가합니다.) 이렇게 모든 객체가 S1 영역으로 이동하면 나머지 eden, s1영역은 클리어 상태가 됩니다.
5. 위의 과정을 계속 반복하다가 살아남는 객체는 S0 영역으로 다시 이동하고, age가 증가됩니다.
6. 이렇게 계속 살아남다가 age가 특정 threshold를 넘으면 Old 영역으로 이동합니다.
Old 영역의 GC 과정
Old 영역에서의 GC는 데이터가 가득 차면 GC를 실행하게 됩니다. GC 방식은 5가지 정도의 방식이 있습니다.
- Serial GC : mark-sweep-compact 알고리즘 사용합니다. old 영역의 살아있는 객체 식별한 뒤 살아있는 거 빼고 다 지우고, 각 객체들이 연속되도록 컴팩트하게 채웁니다. 이는 적은 메모리와 CPU 코어 개수가 적을 때 적합한 방법입니다.
- Parallel GC : 위 Serial GC와 방식은 같지만 Serial은 하나의 스레드로 처리되지만, 여러개의 스레드를 사용해 빠르게 처리 가능
- CMS GC : 4가지의 단계로 구성되어 있습니다.
Initial Mark : 클래스 로더에서 가장 가까운 객체 중 살아 남는 객체를 찾음
Concurrent Mark : 방금 살아있다고 확인한 객체에서 참조학고 있는 객체를 따라가며 확인
Remark : 위 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인
Concurrent Sweep : 쓰레기들을 정리
이것은 다른 GC보다 stop-the-world시간이 짧고 속도가 빠르지만, compaction단계가 제공되지 않으며 다른 GC보다 메모리와 CPU소모가 많습니다.- G1 GC : 위에서 얘기한 Young, old 영역으로 나눈 GC가 아니고, 바둑판의 각 영역에 객체를 할당하고 GC를 실행합니다. 그러다가 해당 영역이 꽉 차면 다른 영역에 객체를 할당학고 GC를 실행합니다. (young에서 old로 이동하는 단계가 사라짐)
이것은 그 어떤 GC보다 빠릅니다. 이것은 자바 7부터 정식으로 나왔지만 실제 기본적인 GC로 사용된 것은 자바 9버전 부터 입니다. (java 7, 8의 기본 GC는 Parallel GC)출처 : d2.naver.com/helloworld/1329, gyoogle.dev/blog/computer-language/Java/Garbage%20Collection.html
'Mhwan's Study > JAVA & Kotlin' 카테고리의 다른 글
[JAVA] Reflection & Serializable (0) 2021.08.10 [Kotlin] Kotlin의 컴파일 과정 & Kotlin VS JAVA (Annotation Processor) (0) 2021.08.09 [JAVA/DataType & String] 데이터 타입과 String에 대해 (0) 2021.01.21 [JAVA/JVM & Compile] JVM과 컴파일 (0) 2021.01.19 [JAVA/Hash] JAVA의 HashMap과 충돌(Collision) 문제 (0) 2021.01.09