Java GC

남해울·2021년 6월 16일
0

Java

목록 보기
1/1

Java GC

가비지 컬렉션 기초

  • Stop-the-world: GC을 실행하기 위해 JVM이 Application 실행을 멈추는 것.
    • stop-the-world가 발생하면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생한다. 대개의 경우 GC 튜닝이란 stop-the-world 시간을 줄이는 것
  • System.gc()을 호출하는 건 시스템 성능을 악영향.
    • Java는 내부 알고리즘에 의해 필요없는(쓰레기) 객체를 정리하기에..
  • GC는 두 가지 전제 조건(weak generational hypothesis) 하에 만들어졌다.
    • 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
    • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.

Weak generational hypothesis의 장점을 위한 영역 분리 - HotSpot VM의 Young 영역과 Old영역

  • Young 영역(Young Generation 영역): 새롭게 생성한 객체의 대부분이 여기에 위치. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 Young 영역에 생성되었다가 사라진다.

    → 이 영역에서 객체가 사라질 때 Minor GC가 발생한다고 말한다.

  • Old 영역(Old Generation 영역): 접근 불가능 상태로 되지 않아 Young영역에서 살아남은 객체가 여기로 복사된다. 대부분 Young영역보다 크게 할당하며, 크기가 큰만큼 Young영역보다 GC는 적게 발생

    → 이 영역에서 객체가 사라질 때 Major GC(Full GC)가 발생한다고 말한다.

  • Permanent Generation 영역(Method Area): 객체나 억류된 문자열 정보(?)

Old영역에 있는 객체가 Young 영역의 객체를 참조하는 경우가 있을 때에는 어떻게 처리될까?

  • Card Table만 뒤져서 GC대상인지 확인
    • 이유: Old영역에 있는 객체가 Young 영역의 객체를 참조할 때마다 Card Table에 정보가 표시된다.
    • Card Table은 512Byte로 이루어진 덩어리(Chunk)이다
  • Card Table은 write barrier를 사용하여 관리되어, Minor GC를 빠르게 할 수 있게 된다.
    • TODO) write barrier란?

Young 영역의 구성

  • Young의 3가지 영역: Eden 영역/Survivor 영역(2개)
  • 각 영역의 처리 절차
    • 새로 생성한 대부분의 객체는 Eden 영역에 위치
    • Eden영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.
      • 반복적으로 GC가 발생하면 Survivor 영역에 쌓인다.
    • Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다. 그리고 가득 찬 Survivor 영역은 아무 데이터도 없는 상태가 된다.
    • 이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.
      • TODO) 질문: 얼마나 반복해야 하나..?

HotSpot VM의 빠른 메모리 할당 기술

  • Bump-the-pointer: Eden 영역에 할당된 마지막 객체를 추적. 마지막 객체는 Eden 영역의 맨 위(top)에 있다. 그리고 그 다음에 생성되는 객체가 있으면, 해당 객체의 크기가 남은 Eden 영역에 넣기 적당한지만 확인한다. 만약 해당 객체의 크기가 적당하다고 판정되면 Eden영역에 넣게 되고, 새로 생성된 객체가 맨 위에 있게 된다.

    → 새로운 객체를 생성할 때 마지막에 추가된 객체만 점검하면 되므로 매우 빠르게 메모리 할당이 이루어짐!

이미지 출처: [Memory management and Garbage Collection](https://www.linkedin.com/pulse/memory-management-garbage-collection-aqib-javed/)

- 예를 들어 Object 1이 할당되면 Pointer는 상단에 놓이게 된다. Object 2가 생성되어 Eden 영역에 들어오려고 할 때 Pointer를 기반으로 남은 영역과 Object 2의 영역을 계산한 다음 Object 2가 더 작다면 Eden Space로 들어오게 하고, 아니면 GC.
- **단점**
    1. Pointer의 위치를 매번 변경해야 한다.
    2. Multi-thread 환경에서는 Thread-safe하기 위해 Lock이 발생할 수 밖에 없고 성능은 매우 떨어질 것이다.
  • TLAB(Thread-Local Allocation Buffer): 각각 Thread가 자신만의 Buffer를 가지고 Bump-the-pointer 기술을 사용함으로서 Thread-safe하고 Fast.

이미지 출처: [Memory management and Garbage Collection](https://www.linkedin.com/pulse/memory-management-garbage-collection-aqib-javed/)

- 각각의 TLAB가 가득차게 되면 Common Area라는 공용 공간으로 객체를 전달하게 된다. 그러다가 Common Area가 가득하게 되면 **minor GC**가 발생하게 된다.

Old 영역에 대한 GC

  • Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행한다. GC 방식에 따라서 처리 절차가 달라지기에 어떤GC 방식이 있는지 살펴보면 이해가 쉬울 것.
  • JDK 7 기준으로 5가지 방식
    • Serial GC
    • Parallel GC
    • Parallel Old GC
    • CMS(Concurrent Mark & Sweep GC)
    • G1(Garbage First) GC

Serial GC(-XX:+UseSerialGC)

  • Old 영역의 GC는 mark-sweep-compact 알고리즘 사용
    1. Mark: Old 영역에 살아 있는 객체를 식별
    2. Sweep: Heap의 앞 부분부터 확인하여 살아 있는 것만 남긴다
    3. Compaction: 각 객체들이 연속되게 쌓이도록 힙의 가장 앞 부분부터 채워서 객체가 존재하는 부분과 객체가 없는 부분으로 나눈다.
  • 오직 하나의 thread를 사용해야 하고 작은 Heap 크기를 가지는 프로그램에서 적합.. 사실상 잘 안씀

Parallel GC(-XX:+UseParallelGC)

  • Mark-sweep-compact 알고리즘을 사용
  • Serial GC는 GC를 처리하는 스레드가 하나인 것에 비해, Parallel GC는 GC를 처리하는 쓰레드가 여러 개.

Parallel Old GC(-XX:+UseParallelOldGC)

  • Mark-Summary-Compaction 알고리즘(TODO) 공부)

CMS GC(-XX:+UseConcMarkSweepGC)

  • 좌측은 Mark-Sweep-Compact, 우측이 CMS GC

  • 단계

    1. Initial Mark: Root Set에 의해 직접 참조되는 객체들을 Marking. 멈추는 시간이 매우 짧음.
      • TODO) Root Set이랑 Reachability 설명
    2. Concurrent Mark: 방금 살아있다고 확인한 객체에서 참조하고 있는 객체들을 따라가면서 확인. 이 단계의 특징은 다른 스레드가 실행 중인 상태에서 동시에 진행.
    3. Remark: Concurrent Mark 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인.
    4. Concurrent Sweep: 쓰레기를 정리. 이 작업도 다른 스레드가 실행되고 있는 상황에서 진행.
  • 장점: 위와 같은 단계로 진행되기에 stop-the-world 시간이 매우 짧다. Application 응답 속도 시간이 매우 중요할 때 CMS GC를 사용, Low Latency GC라고도 부른다.

  • 단점

    • 다른 GC 방식보다 메모리와 CPU를 더 많이 사용한다.
    • Compaction 단계가 기본적으로 제공 X
      • ?? 뒤에는 무슨 소린지..ㅠ

G1 GC

  • G1 GC를 이해하려면 지금까지의 Young 영역과 Old 영역에 대해서는 잊는 것이 좋다.

  • 위 그림과 같이 G1 GC는 바둑판의 각 영역에 객체를 할당하고 GC를 실행한다. 그러다가, 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 GC를 실행한다.
  • 여기서는 Young의 세가지 영역에서 데이터가 Old 영역으로 이동하는 단계가 사라졌다.
  • 장점: 성능
    • 지금까지 말한 어떤 GC보다 가장 빠르다.

마치며

  • 어떤 서비스에서 A라는 GC 옵션을 적용해서 잘 동작한다고 그 GC 옵션이 다른 서비스에서도 훌륭하게 적용되어 최적의 효과를 볼 수 있다고 생각하지 말라는 것.
  • Oracle JVM 엔지니어 왈: 각 서비스의 WAS에서 생성하는 객체의 크기와 생존 주기가 모두 다르고, 장비의 종류도 다양하다. WAS의 스레드 개수와 장비당 WAS 인스턴스 개수, GC 옵션 등은 지속적인 튜닝과 모니터링을 통해서 해당 서비스에 가장 적합한 값을 찾아야 한다.
profile
열정있는 개발자

0개의 댓글