고딩왕 코범석

Garbage Collection 정리 본문

Language & Framework/JAVA

Garbage Collection 정리

고딩왕 코범석 2021. 12. 11. 20:53
반응형

Garbage Collection

C / C++언어와 달리, 자바는 개발자가 직접 객체를 메모리 공간에서 해제할 일이 없다. 더 이상 참조하지 않는 객체를 자동으로 삭제하는 작업을 Garbage Collection 이라고 부르며, JVM에서 수행한다. 참고로 GC를 해도 더이상 사용 가능한 메모리 영역이 없는데 계속 메모리를 할당하려 하면, OutOfMemoryError가 발생하여 WAS가 다운될 수 있다.


JVM의 Runtime Date Area는 Method, Heap, Method Stack, PC Register, Native Method Stack 이렇게 5개의 영역이 존재하지만 GC는 Heap 영역만 다룬다.

image


일반적으로 메모리 영역에 해제되는 객체는 다음과 같다.


  1. 객체가 Null인 경우
  2. 블럭 실행 종료 후, 블럭 내부에 생성된 객체
  3. 부모 객체가 Null일 경우 포함하는 자식 객체

GC의 메모리 해제 과정을 알아보기 전에 Stop-the-world에 대해 짚고 넘어가자.

🧐 Stop-the-world ???

Garbage Collector를 실행하기 위해 JVM이 애플리케이션의 실행을 멈추고, GC를 실행하는 쓰레드를 제외하고 나머지 모든 쓰레드는 작업을 멈춘다. GC가 안쓰는 객체의 메모리를 모두 해제하고 나서, 중단했던 애플리케이션을 다시 실행한다. 어떤 GC 알고리즘을 사용하더라도 이 Stop-the-world는 항상 발생하며, GC 튜닝이란 이 Stop-the-world 시간을 줄이는 것이다.

🪙 객체의 참조

GC는 객체가 사용되거나 사용되지 않는 상태를 구분하여 제거하는데, 참조하는 유형에 따라 구분짓고 그 정도를 Reachability 로 표현하고 있다. Heap 영역에 존재하는 객체들에 대한 참조는 다음 4가지 종류중 하나이다.


  1. Heap 영역 내의 다른 객체에 의한 참조
  2. 스택 영역의 Java 메서드 내에 실행하는 지역 변수, 파라미터, 연산 작업중 피연산자에 의한 참조
  3. 메서드 영역의 상수 풀이나 정적 변수에 의한 참조
  4. 아직 메모리에 남아있는 Native 메서드로 넘겨진 객체에서 참조

image


이 중 Heap 영역 내의 다른 객체에 의한 참조의 경우를 제외하고 나머지 세 경우가 Reachability를 판가름하는 시작점이 된다. 이 시작점으로부터 어떻게든 참조 관계가 있다면 객체가 사용되는 상태(Reachable), 참조가 끊어져있다면 사용되지 않는 상태(Unreachable)라고 한다.

🪜 GC의 메모리 해제 과정 (Mark-Sweep-Compaction)

1. Marking

image


프로세스가 Marking을 호출한다. GC가 객체들이 메모리에서 사용되는지, 안되는지를 체크하며 모든 오브젝트들은 이 단계에서 메모리를 해제할지 말지에 대해 결정을 위해 스캔된다. 모든 오브젝트를 스캔하기에 많은 시간이 소요된다.


2. Normal Deletion (Sweep)

image


참조되지 않는 객체를 제거하고 메모리를 반환한다. Memory Allocator가 비어진 블럭의 참조 위치를 저장해두고, 새로운 오브젝트가 선언되면 할당되도록 한다.


3. Compacting

image


성능을 향상시키기 위해 참조되지 않는 객체들을 제거 후 남은 참조되어지는 객체들을 묶는다. 이를 묶음으로써 공간이 생겨 메모리 할당 시 더 빠르게 진행할 수 있다.

🧐 Weak Generational Hypothesis

위와 같이 모든 객체들을 Mark, Compact하는 것은 굉장히 비효율적이다. 신규로 생성한 객체의 대부분은 금방 사용하지 않는 상태가 되고, 오래된 객체에서 신규 객체로의 참조는 매우 적게 존재한다는 가설에 기반하여 자바는 Young / Old 영역으로 메모리를 분할하고, 신규로 생성되는 객체는 Young, 오랫동안 살아남은 객체는 Old 영역에 보관한다.

🪥 Generational Garbage Collection

Permanent는 Heap이 아니며, Java 8 이후로는 Permanent 영역은 Metaspace 영역으로 대체되었다.


image


1. Young Generation

image


Young Generation 영역은 eden 영역과 S0, S1 영역 총 세 가지로 분류되며, 이 영역에서 객체가 사라질 때는 Minor GC가 발생한다고 말한다. 그리고 각 영역의 처리 절차 순서는 다음과 같다.


  1. 새로 생성한 대부분의 객체는 Eden 영역에 위치
  2. Eden 영역이 꽉차면 Minor GC가 발생하고 살아남은 객체는 S0 or S1로 이동 (GC가 발생할 때 마다 S0 or S1 영역에 계속 쌓이게 됨)
  3. 둘 중 하나의 Survivor 영역이 가득 차게 되면, 그 중 살아남은 객체를 다른 Survivor 영역으로 이동한다. 그리고 이 가득찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.
  4. 이 과정을 반복하여 살아남은 객체는 Old 영역으로 이동한다.

2. Old Generation


Young Generation 영역에서 살아남은 객체들이 이동하는 곳이며, 공간을 Young Generation 영역보다 크게 할당한다. 여기서 객체가 사라질 때는 Full GC 혹은 Major GC가 발생한다고 말한다. 그리고 이 Old Generation 영역은 데이터가 가득 찰 때, GC를 실행하고 어떤 GC냐에 따라 처리 절차가 달라진다.

GC 종류

GC의 종류는 다음과 같다.

  • Serial GC
  • Parallel GC
  • Parallel Old GC
  • Concurrent Mark & Sweep GC
  • G1 GC
  • Z GC

이 중 간단하게 살펴볼 GC는 Java 8 에서 기본으로 사용되는 Parallel GC와 G1 GC 이다.

1. Parallel GC

앞에서 설명한 GC의 메모리 해제 과정과 같다. 하지만 이름에서 알 수 있듯, 여러 개의 쓰레드로 Mark-Sweep-Compaction을 수행한다. 이로 인해 Stop-the-world 시간이 현저히 줄어들게 된다. Parallel GC는 메모리가 충분하고 코어의 갯수가 많을 때 유리하다.

2. G1 GC

하드웨어가 발전되어 JVM을 가동하는 메모리의 크기도 커져가는데, 이전까지의 GC들은 큰 용량의 메모리에 적합하지 않다. G1 GC는 이런 점을 개선하여, 큰 Heap 메모리에서 짧은 GC 시간을 보장하는데 그 목적을 둔다. 앞에서 살펴본 Eden, Survivor, Old 영역이 G1 GC에도 존재하지만 고정된 크기로 고정된 위치에 존재하지 않는다.

image


전체 Heap 영역을 Region 이라는 특정한 크기로 나누어 각 Region의 상태에 따라 역할이 동적으로 부여된다. Eden, Survivor, Old 이외에도 Humonogous와 Available/Unused Region이 추가로 보이는데, Young 영역에서 GC가 수행되면 Stop-the-world 현상이 발생하고 이 시간을 줄이기 위해 멀티스레드로 GC를 수행한다. 이 때, G1 GC의 경우 비워진 Region에 대해서는 Available/Unused Region 상태로 돌리게 되고, Humonogous는 설정된 Region의 크기의 50%를 초과하는 큰 객체를 저장하기 위한 장소이다.


출처

반응형

'Language & Framework > JAVA' 카테고리의 다른 글

JVM 정리  (0) 2021.12.11