시냅스

Java 가비지 컬렉션 Garbate Collection 정리 본문

Java, Spring

Java 가비지 컬렉션 Garbate Collection 정리

ted k 2023. 2. 8. 21:48

GC

 

  • stop the world
    • GC를 실행하기 위해 JVM이 애플리케이션의 실행을 멈춤
    • gc를 실행하는 쓰레드를 제외한 나머지 쓰레드는 작업을 멈춤
    • 어떤 GC 알고리즘을 사용하더라도 꼭 발생
    • 대개의 GC 튜닝은 이 시간을 줄이는 것

 

 

  • 가비지 컬렉터의 실행 조건
    • JVM이 OS로부터 메모리를 부여 받고 프로그램을 실행하다가 메모리가 부족하여 OS에게 추가로 메모리를 요청하는 시점에 실행된다.
    • 혹은 JVM의 idle time에 실행된다.
    • dangling object가 그 대상이다.

 

 

  • System.gc() 를 호출해선 안된다.
    • System.gc() 는 garbage collection 을 실행하는 함수
    • 자바에서는 명시적으로 메모리를 지정하여 해제하지 않기 때문에
    • 객체를 null 로 지정하거나 System.gc() 를 호출하여 메모리 해제
    • 단 System.gc()는 시스템 성능에 매우 큰 영향을 끼치므로 사용해서는 안된다.

 

 

  • Young 영역과 Old 영역
    • 가비지 컬렉터는 두 가지 가정 하에 만들어졌다.
      • 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
      • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
      • 이러한 가설을 weak generational hypothesis라 한다.
      • 위 가정을 최대한 살리기 위해 HotSpot VM(JVM의 종류)에서는 물리적 공간을 Young과 Old 영역으로 크게 2개로 나눴다.
    • Young (Young Generation) 영역
      • 새롭게 생성한 객체의 대부분은 여기에 위치한다.
      • 대부분의 객체가 금방 접근 불가능 상태(e.g. for문 안의 객체, 함수 내부의 객체 등)가 되기 때문에 young 영역에서 생성되었다가 사라진다.
      • 여기에서 사라질 때 minor gc가 발생했다고 말한다.
    • Old (Old Generation) 영역
      • 접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체는 여기로 복사된다.
      • 대부분 Young 영역보다 크게 할당한다.
      • 크기가 큰 만큼 Young 영역보다 GC는 적게 발생
      • 여기에서 사라질 때 major gc가 발생했다고 한다.
    • Permanent (Permanent Generation) 영역
      • method 영역이라고 하기도 한다.
      • 객체나 억류된 문자열 정보(String.inter == string pool 에 넣는다)를 저장하는 곳
      • old 영역에서 살아남은 객체가 영원히 저장되는 공간은 아니다
      • 이 영역에서 GC가 발생해도 major gc count에 포함된다.
      • java 8 에선 metaspace로 교체됨
        • classloader가 현재까지 로드한 class들의 metadata가 저장되는 공간
        • metaspace 는 jvm이 아닌 OS에서 관리하는 native 메모리 영역
        • heap이 아니라 native 메모리(시스템의 기본 메모리) 영역에 위치
        • default로 제한된 크기를 갖고 있지 않고, 필요한 만큼 늘어남
        • java 8 부턴 permgen 관련 jvm 옵션은 무시한다.

 

 

  • Old 영역에 있는 객체가 Young 영역의 객체를 참조하는 경우
    • Old 영역은 512 바이트의 chunk로 되어있는 카드 테이블이 있다.
    • old 영역 객체가 young 영역의 객체를 참조할 때 마다 카드 테이블에 정보를 표시한다.
    • Young 영역의 GC를 실행할 때에는 old 영역에 있는 모든 객체의 참조를 확인하지 않고 카드 테이블만 뒤져서 GC 대상인지 식별한다.

 

 

  • Young 영역의 구성
    • Young 영역은 3개의 영역으로 나뉜다.
      • Eden 영역
      • Survivor 영역 (2개)
    • 각 영역의 처리 절차 순서는 다음과 같다.
      • 새로 생성한 대부분의 객체는 Eden 영역에 위치한다.
      • Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동한다.
      • 위의 Survivor 영역으로 객체가 계속 쌓인다.
      • 하나의 Survivor 영역이 가득 차면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다.
      • 그리고 가득 찬 survivor 영역은 아무 데이터도 없는 상태로 된다.
      • 이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.
      • Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아야 한다.
    • 참고
      • bump-the-pointer
        • 객체를 stack으로 관리하여 메모리 할당 후 맨 위에 넣어 다음 객체 생성 시에 가장 위의 객체를 보고 eden 영역에 적합한지 판단하여 메모리 할당을 빠르게 하는 기술
      • TLAB
        • 각각의 스레드가 각자의 eden 영역의 작은 덩어리를 가질 수 있게 해서 각 스레드에서 bump-the-pointer 를 사용하더라도 thread safe 하게 만든다

 

 

  • Old 영역에 대한 GC
    • 방식은 jdk 7 기준으로 5가지이다.
      • Serial GC
        • 운영 서버에서 절대 사용해선 안된다
        • 싱글코어 전용
      • Parallel GC
        • mark - sweep - compacting 순서
        • Old 영역에 살아 있는 객체를 식별(Mark) 한다
        • 그 다음에는 heap의 앞 부분부터 확인하여 살아 있는 것만 남긴다 (Sweep)
        • 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다. (compacting)
      • Parallel Old GC(Parallel Compacting GC)
        • mark - summary - compacting
        • 위의 sweep과 summary가 다른 점은 앞서 gc를 수행한 영역에 대해서 별도로 살아 있는 객체를 식별한다는 점과 약간 더 복잡한 단계를 거친다는 점이다.
      • Concurrent Mark & Sweep GC (CMS)
        • 위의 mark - sweep 을 concurrent 하게 실행한다
        • initial mark 에서 객체를 확인하고
        • concurrent mark에서 스레드가 실행 중인 상태에서 확인하고
        • remark에서 새로 추가되거나 끊긴 객체를 확인하여
        • concurrent sweep 으로 다른 스레드가 실행되는 와중에 정리하는 작업을 실행한다.
        • 다른 GC보다 리소스 사용량이 많고, compacting이 기본적으로 제공되지 않는다.

 

 

  • G1(Garbage First) GC

  • java 9 이후부터 default gc
  • heap을 일정크기의 region으로 잘게 나누어서 관리
    • 어떤 부분은 old, 어떤 부분은 young
    • 각 바둑판에 eden, survivor, old를 따로 두어 이동시키거나 삭제함
  • G1 GC는 바둑판의 각 영역에 객체를 할당하고 gc를 실행한다. 그러다가, 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 gc를 실행한다.

 

정리

  • mark and sweep
    • root로 부터 연결이 되어있는 객체는 놔두고 끊어진 객체들은 지운다
    • old 영역에서 실행된다.
    • 따라서 mark and sweep 혹은 major gc 시간을 짧게 유지해야 한다.
  • young 영역에서는 카드 테이블을 조회하여 참조가 없으면 minor gc를 실행한다.
    • age-bit
      • young 영역에 있는 객체가 old 영역으로 넘어가는 기준
      • 높을 수록 오래도록 참조될 객체로 old 영역에 넘어갈 확률이 높다
    • 참조 지역성의 원리로 minor gc가 훨씬 자주 일어난다.
Comments