[JAVA] Java Garbage Collection 동작 과정

보라보라·2024년 2월 20일
0

GC

목록 보기
2/3
post-thumbnail

Garbage Collection 동작 방식

지난 글에서 GC에 의미와, GC의 대상
그리고 java에서 GC의 대상을 찾는 [Mark And Sweep] 특징에 대해 알아보았다.
특징 중 첫번째인 "의도적으로 GC를 실행시켜야한다." 는 특징이 있다.
그래서 이번 글에서는 GC의 구동방식이 어떻게 되는지 알아볼 것이다.
설명 할 내용을 아래 그림이 압축적으로 보여준다. 일단 눈에 익혀보자.

Heap 메모리의 구조

Heap 영역

  • 가비지 컬렉션에 대상이 되는 공간이다.
  • 동적으로 레퍼런스 데이터가 저장되는 공간이다.

Heap 메모리 영역

Heap영역의 2가지 설계 전제(Weak Generational Hypothesis)

  1. 대부분의 객체는 금방 Unreachable이 된다.
    즉, 금방 garbage가 된다.
  2. 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

객체는 대부분 일회성되며, 메모리에 오랫동안 남아있는 경우는 드물다는 것이다.

이러한 특성을 이용해 JVM 개발자들은 보다 효율적인 메모리 관리를 위해, 객체의 생존 기간에 따라 물리적인 Heap 영역을 나누게 되었고 Young 과 Old 총 2가지 영역으로 설계하였다.

Young 영역(Young Generation)

  • 새롭게 생성된 객체가 할당(Allocation)되는 영역
  • 대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
  • Young 영역에 대한 가비지 컬렉션(Garbage Collection)을 Minor GC라고 부른다.

Old 영역(Old Generation)

  • Young 영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
  • Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
    • Young 영역의 수명이 짧은 객체들은 큰 공간을 필요로 하지 않으며 큰 객체들은 Young 영역이 아니라 바로 Old 영역에 할당되기 때문
  • Old 영역에 대한 가비지 컬렉션(Garbage Collection)을 Major GC 또는 Full GC라고 부른다.

Young Generation의 분류

Eden 

  • 쉽게 객체가 태어나는 곳!
  • new를 통해 새로 생성된 객체가 위치. 
  • 정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor 영역으로 보냄

Survivor 0 / Survivor 1

  • 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
  • Survivor 영역에는 특별한 규칙이 있는데, Survivor 0 또는 Survivor 1 둘 중 하나에는 꼭 비어 있어야 하는 것이다.

이렇게 하나의 힙 영역을 세부적으로 쪼갬으로서 객체의 생존 기간을 면밀하게 제어하여 가비지 컬렉터(GC)를 보다 정확하게 불필요한 객체를 제거하는 프로세스를 실행하도록 한다.

[Java8 에서의 Permanent 영역]
Permanent는 직역하면 영구적인 세대의 의미로서, 생성된 객체들의 정보의 주소값이 저장된 공간이다. 클래스 로더에 의해 load되는 Class, Method 등에 대한 Meta 정보가 저장되는 영역이고 JVM에 의해 사용된다. Java 7 까지는 힙 영역에 존재했지만 Java 8 버전 이후에는 Native Method Stack에 편입되게 된다.
Java8부터는 MetaSpace영역이 추가되었다. 이 영역에서는 Class들의 Metadata가 저장되는 곳이다.

  • java 7 HotSpot JVM
<----- Java Heap ----->             <--- Native Memory --->
+------+----+----+-----+-----------+--------+--------------+
| Eden | S0 | S1 | Old | Permanent | C Heap | Thread Stack |
+------+----+----+-----+-----------+--------+--------------+
                        <--------->
                       Permanent Heap
S0: Survivor 0
S1: Survivor 1
  • Java 8 HotSpot JVM
<----- Java Heap -----> <--------- Native Memory --------->
+------+----+----+-----+-----------+--------+--------------+
| Eden | S0 | S1 | Old | Metaspace | C Heap | Thread Stack |
+------+----+----+-----+-----------+--------+--------------+

-> 이 부분도 더 찾아볼 것!

Minor GC 과정

Young Generation 영역에서 발생되는 GC를 Minor GC라 함.

  1. 처음 생성된 객체는 Young Generation 영역의 일부인 Eden 영역에 위치

  2. 객체가 계속 생성되어 Eden 영역이 꽉차게 되고 Minor GC가 실행

  3. Mark 동작을 통해 Reachable 객체를 탐색

  1. Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동
  1. Eden 영역에서 사용되지 않는 객체(unreachable)의 메모리를 해제(Sweep)
  1. 살아남은 모든 객체들은 age값이 1씩 증가

[age]

  • Survivor 영역에서 객체의 객체가 살아남은 횟수를 의미하는 값이며, Object Header에 기록된다.
  • 만일 age 값이 임계값에 다다르면 Promotion(Old 영역으로 이동) 여부를 결정한다.
  • JVM 중 가장 일반적인 HotSpot JVM의 경우 이 age의 기본 임계값은 31이다.
    • 객체 헤더에 age를 기록하는 부분이 6 bit로 되어 있기 때문이다.

  • Survivor 영역의 제한 조건으로
    • Survivor 영역 중 반드시 1개는 사용되어야 하고, 나머지는 비어 있어야 한다.
    • 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 현재 시스템이 정상적인 상황이 아니라는 반증이 된다.
  1. 또다시 Eden 영역에 신규 객체들로 가득 차게 되면 다시한번 minor GC 발생하고 mark 한다

  2. marking 한 객체들을 비어있는 Survivor 1으로 이동하고 <-(sweep)

  1. 다시 살아남은 모든 객체들은 age가 1씩 증가
  1. 이러한 과정을 반복

Major GC 과정

  • 길게 살아남는 메모리들이 존재하는 공간이다.
  • Old Generation의 객체들은 거슬러 올라가면 처음에는 Young Generation에 의해 시작되었으나, GC 과정 중에 제거되지 않은 경우 age 임계값이 차게되어 이동된 녀석들이다.
  • Major GC는 객체들이 계속 Promotion되어 Old 영역의 메모리가 부족해지면 발생하게 된다.
  1. Minor GC가 반복적으로 일어나면 객체의 age가 임계값(여기선 8로 설정)에 도달하게 된다.
  1. Young Generation에서 살아남은 객체들은 이 객체들은 Old Generation 으로 이동된다. 이를 promotion 이라 부른다.
  1. 위의 과정이 반복되어 Old Generation 메모리가 가득 차게 되면 Major GC가 발생되게 된다. 이 때도 마찬가지로 Mark and Sweep방식을 통해 필요 없는 메모리를 비워준다.
  • Major GC는 Old Generation 데이터가 가득 차면 GC를 실행하는 방식

Minor GC와 Major GC

GC 종류Minor GCMajor GC
대상Young GenerationOld Generation
실행 시점Eden영역이 가득 찬 경우,
Survivor영역이 가득 찬 경우
Old영역이 가득 찬 경우
실행 속도빠르다느리다
  • Major GC는 Minor GC보다 더 오래 걸리게 됨.
    • Old Generation은 Young Generation에 비해 상대적으로 큰 공간을 가지고 있어, 이 공간에서 메모리 상의 객체 제거에 많은 시간이 걸리게 된다.
    • Young 영역은 일반적으로 Old 영역보다 크키가 작기 때문에 GC가 보통 0.5초에서 1초 사이에 끝난다. 그렇기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않는다.
    • 하지만 Old 영역의 Major GC는 일반적으로 Minor GC보다 시간이 오래걸리며, 10배 이상의 시간을 사용한다.

결론

Minor GC와 Major GC의 비교로써 Major GC의 시간이 오래걸리게 되고, 앞 글에 소개했던 Stop-The-World 문제가 발생하게 된다.
Major GC가 일어나면 Thread가 멈추고 Mark and Sweep 작업을 해야 해서 CPU에 부하를 주기 때문에 멈추거나 버벅이는 현상이 일어나기 때문이다.
따라서 자바 개발진들은 끊임 없이 가비지 컬렉션 알고리즘을 발전 시켜왔다.
이 다음글에서 GC의 알고리즘에 대해 알아보도록 하겠다.


출처:

profile
쉽게쓰려고 노력하는 블로그

0개의 댓글