[JAVA] Garbage Collection

hyng·2022년 4월 4일
0

GC(Garbage Collection)?

java에서는 개발자가 직접 메모리 관리를 하지 않고 jvm의 Garbage Collector가 프로그램에서 접근하지 않는 메모리를 정리해 준다.

그럼 GC는 어떤 과정으로 이뤄지는 것일까?

JVM 내의 모든 object들을 확인해서 reachable object를 mark 하고 mark 하지 않은, 즉 unreachable object를 삭제하는 식으로 하면 더 이상 프로그램에서 사용하지 않는 메모리를 해제할 수 있을 것이다.
근데 이 방법은 너무 시간이 많이 드는 작업이다.
프로그램이 점점 커진다면 JVM 내에 존재하는 object들도 증가하게 될 텐데 Garbage Collection을 할 때마다 모든 object를 확인하는 것은 비효율적이다.


출처
그리고 대부분의 객체는 금방 unreachable이 된다.
그래서 객체 생존기간에 따라 heap을 young(Eden, Survival0, Survival1), old로 물리적으로 나누는 방식이 나오게 되었다.


출처

기본적으로 GC 과정은 아래 순서를 따른다.

  1. Mark And Sweep
    1) Mark

    출처
    스택의 모든 변수와 reachable object가 레퍼런스 하고 있는 object를 marking하는 것이다.

    2) Sweep

    출처
    1번에서 mark되지 않은 = unreachable object 메모리를 해제하는 것이다.

Heap 각 영역 소개


출처

  1. Young generation: 객체들의 age가 증가하고, 해당 영역이 가득 찰 경우 Minor Garbage Collection이 발생합니다.
    1) Eden: 새롭게 생성된 객체가 할당되는 영역
    2) Survival0, Survival1: Eden 영역이 가득 차게 되어 Minor Garbage Collection이 발생할 때 Eden 영역에 존재하는 모든 reachable object를 mark 하게 됩니다. 그리고 mark된 객체들을 Survival0으로 옮기고 Eden에 남은 unreachable object 메모리를 해제합니다.
    그러다 어느 순간 Survival0도 가득 차게 되면 같은 과정을 Survival0 -> Survival1로 반복합니다.
    이런 식의 과정을 반복하면서 살아남은 객체들의 age는 object header에 1씩 더하여 저장되게 됩니다.
  2. Old generation: 살아남은 객체들의 age가 정해놓은 임곗값을 넘으면 Old generation으로 옮겨지게 됩니다.
    이런 식으로 Old 영역에 살아남은 객체들이 옮겨지다 보면 해당 영역도 어느 순간 다 차게 되는데 그때는 Major Garbage Collection이 발생하게 됩니다.

그렇다면 "Old 영역에 있는 객체가 Young 영역의 객체를 참조하는 경우가 있을 때에는 어떻게 처리될까?"라고 궁금해 하는 분도 더러 있을 것이다. 이러한 경우를 처리하기 위해서 Old 영역에는 512바이트의 덩어리(chunk)로 되어 있는 카드 테이블(card table)이 존재한다.
카드 테이블에는 Old 영역에 있는 객체가 Young 영역의 객체를 참조할 때마다 정보가 표시된다. Young 영역의 GC를 실행할 때에는 Old 영역에 있는 모든 객체의 참조를 확인하지 않고, 이 카드 테이블만 뒤져서 GC 대상인지 식별한다.
출처: https://d2.naver.com/helloworld/1329


출처

Minor Garbage Collection, Major Garbage Collection 발생할 때 stop the world이벤트가 발생하게 됩니다.
stop the world는 gc를 실행하는 스레드 이외 모든 스레드가 실행 중지되는 것입니다.
대게 gc 튜닝은 stop the world 시간을 줄이는 것을 뜻합니다.

GC 알고리즘

1. Serial GC

  • Garbage Collection을 싱글 스레드로 순차적으로 실행한다.
  • Major Garbage Collection에서 mark-compact를 사용한다.
    compact는 mark-sweep 과정 이후 유효한 객체들이 연속되게 쌓이도록 히프의 가장 앞 부분부터 채워서 객체가 존재하는 부분과 객체가 존재하지 않는 부분으로 나누는 것이다.
  • 적은 메모리와 CPU 코어 개수가 적을 때 사용하는 방식이다.

    출처

2. Parallel GC

  • 기본적인 처리 과정은 Serial GC와 같다.
  • Minor Garbage Collection에서 멀티 스레드를 사용하기 때문에 stop the world 이벤트로 인해 발생하는 정지 시간을 줄여줄 수 있다.

3. CMS(Concurrent Mark Sweep) GC


출처

  • 대부분 Garbage Collection 작업을 애플리케이션 스레드와 동시에 실행함으로써 stop the world 이벤트로 인한 정지시간을 최소화한다.
  • Compact 과정이 없기 때문에 만약 메모리 파편화가 문제가 된다면 더 큰 heap를 할당하거나 Compact를 해야 하는데 이렇게 할 경우 오히려 stop the world 시간이 더 길어지는 문제가 발생한다.

4. G1 GC

  • G1 GC는 heap을 같은 크기의 region으로 나누고 논리적으로 구분(eden, survivor, old, Humongous와 Availabe/Unused)한다.
  • Humonguous는 Region 크기의 50%를 초과하는 객체를 저장하는 Region을 의미하며, Availabe/Unused는 사용되지 않은 Region을 의미한다.
  • garbage가 대부분인 영역(가장 효율적인 영역)을 먼저 회수한다.
  • Eden 영역이 꽉 찰 경우 살아남은 객체들을 다른 region으로 옮기는데 그 region이 Availabe/Unused라면 해당 region은 Survivor이 되고 Eden 영역은 Availabe/Unused이 된다.
  • 모든 region을 추적하기 때문에 Major Garbage Collection에서 전체 heap영역을 GC를 하지 않고 GC를 수행할 region을 조합하여 해당 region에 대해서만 GC를 수행한다.
    "The Garbage-First Garbage Collector" (TS-5419), JavaOne 2008, p. 19)

참고

https://d2.naver.com/helloworld/1329
https://yaboong.github.io/java/2018/06/09/java-garbage-collection/
https://mangkyu.tistory.com/118
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글