Today
-
Yesterday
-
Total
-
  • 💡 [CS지식] Garbage Collection에 대하여
    | 자료구조 & 알고리즘/Computer Science 2021. 10. 26. 09:44

    Garbage Collection

    Java에선 개발자가 프로그램 코드로 메모리를 명시적으로 해제하지 않아요
    JVM(Java Virtual Machine)이 구성된 JRE(Java Runtime Environment)가 제공되며, 그 구성 요소 중 하나인 Garbage Collection(이하 GC)이 자동으로 사용하지 않는 객체를 메모리에서 삭제하는 작업을 수행해요

    기본적으로 JVM의 메모리는 총 5가지 영역(class, stack, heap, native method, PC)으로 나뉘는데, GC는 힙 메모리만 다뤄요

    Generational Garbage Collection

    Java application에서는 가비지 컬렉션을 통해 더이상 사용되지 않는 오브젝트들을 제거해요.

    가비지 컬렉션에서 '더이상 사용되지 않는'의 의미는 'Unreachable object'라고 말할 수 있어요. Unrechable object들은 Stack에 도달할 수 없는 Heap영역의 객체단위라고 할수 있어요.

    • 객체가 NULL인 경우
    • 객체가 블럭 안에서 생성되고 블럭이 종료되었을 경우
    • 부모 객체가 NULL이 되었을 경우, 자식 또는 포함된 객체들

    GC의 과정

    deallocating memory과정은 가비지 컬렉터에 의해 자동으로 실행돼요

    • Step 1: Marking
      • 가비지 컬렉터는 메모리에서 live object를 확인 하고, unrechable object가 무엇인지 마킹하는 절차를 진행해요
    • Step 2: Normal Deletion
      • 가비지 컬렉터는 unrechable object를 삭제해요
    • Step 2a: Deletion with Compacting
      • 가비지 컬렉터중 일부는 memory를 더욱 효과적으로 쓰기위해 unreachable object를 삭제함과 동시에 압축을 진행하기도 해요

    Weak Generational Hypothesis

    모든 객체를 Mark & Compact하는 방식의 Garbage Collection은 규모가 큰 프로그램에서 심각한 문제가 생길 수 있어요. JVM GC 설계자들은 경험적으로 대부분의 객체가 생겨나자마자 쓰레기가 된다는 것을 알고 있었어요

    Weak Generational Hypothesis는 신규로 생성한 객체의 대부분은 금방 사용하지 않는 상태가 되고, 오래된 객체에서 신규 객체로의 참조는 매우 적게 존재한다는 가설이에요. 이 가설에 기반하여 Java는 Young 영역과 Old 영역으로 메모리를 분할하고, 신규로 생성되는 객체는 Young 영역에 보관하고, 오랫동안 살아남은 객체는 Old 영역에 보관해요.

    1. Young Generation 영역 Heap영역
      • Eden/Survivor0/Survivor1 3개의 영역으로 구분돼요. 이때, Survivor영역 중 하나는 항상 비어있어요.
      • 새로 생성된 객체는 Eden영역에 할당돼요.
      • 많은 객체가 Young영역에 생겼다가 Unreachable상태가 되어 사라져요. Young영역에서 객체가 사라질 때 Minor GC가 발생한다고 말해요.
      • Eden영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor영역 중 하나로 이동해요.
      • Minor GC는 Survivor영역도 같이 검사해서 살아남은 객체는 다른 Survivor영역으로 이동시켜요. 기존의 영역은 빈 상태가 돼요.
      • 위의 과정을 반복하며 계속 살아남은 객체는 Old영역으로 이동해요.
    2. Old Generation 영역 Heap영역
      • 대부분 Young영역보다 크게 할당돼요.
      • Old영역에서 발생하는 Minor GC는 Young영역보다 GC가 적게 발생하고 시간이 오래 걸려요.
      • Unreachable상태가 되지 않고 Young영역에서 오래 살아남은 객체가 여기로 복사돼요.
      • Minor GC : Old영역이 가득 차면 Old영역의 모든 객체들을 검사하여 참조되지 않은 객체들을 한꺼번에 삭제해요. 이때, GC를 실행하는 스레드를 제외한 모든 스레드는 작업을 멈추는데 이를 'stop-the-world' 라고 해요.'stop-the-world'시간을 줄이는 것이 GC튜닝!
    3. Metaspace 영역
      • Java8부터 Permanent영역이 Metaspace 영역으로 변경되었어요.
      • Metaspace 영역은 Native메모리 영역으로, JVM이 아닌 OS에 의해 관리되도록 변경되었어요. (주로 메타데이터)
      • Static Object만 Heap영역 으로 옮겨졌고 최대한 GC의 대상이 될 수 있게 했어요.참조 JDK 8에서 Perm 영역은 왜 삭제됐을까

    Generational Garbage Collection 과정

    1. 새로운 객체가 들어오면 Eden space에 할당돼요. 두 개의 Survivor space는 비워진 상태로 시작해요.1
    2. Eden space가 가득 차게 되면, Minor Garbage Collection이 시작돼요.2
    3. 참조되는(reachable) 객체들은 첫 번째 survivor(S0)로 이동하고, 비 참조(unreachable) 객체는 Eden space가 clear 될 때 함께 메모리에서 사라져요.3
    4. 다음 Minor GC 때, Eden space에서 3번과 같은 과정이 발생한다. 비 참조 객체들은 지워지고, 참조 객체들은 Survivor space로 이동해요. 기존에 S0에 있던 참조 객체들은 S1으로 옮겨지는데, 이때 age 값이 증가되어 옮겨져요. 살아남은 모든 객체들이 S1으로 모두 옮겨지면 S0과 Eden space는 clear 돼요.4
    5. 다음 Minor GC가 발생하면 4번 과정이 반복되는데, S1이 가득 차 있었으므로 S1에서 살아남은 객체들은 S0으로 옮겨지면서 Eden과 S1은 clear 돼요. 이때도 age 값이 증가되어 옮겨져요.
      5
    6. 💡 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 해요. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 시스템이 정상적인 상황이 아니라고 생각하면 돼요.
    7. Young Generation에서 계속해서 살아남으며 age 값이 증가하는 객체들은 age 값이 특정값 이상이 되면 Old Generation(Java 8까지는 Tenured Generation이라 부름)으로 옮겨지는데 이 단계를 Promotion(진급)이라고 해요.6
    8. Minor GC가 계속해서 반복된다면, Promotion 작업도 꾸준히 발생하게 돼요.7
    9. Promotion 작업이 게속해서 반복되면서 Old Generation이 가득 차게 되면 Major GC가 발생하게 돼요. 그렇게 Old Generation이 clear 되고 공간이 compact 돼요.8
sangilyoon.dev@gmail.com