Garbage Collection

이혜수·2022년 9월 19일
0

1.Garbage 란?

  • 앞으로 사용되지 않는 객체의 메모리를 Garbage라고 한다.

2. Garbage 컬렉션이란?(GC라고 함)

자바의 메모리 관리기법으로 어플리케이션이 동적으로 할당했던 메모리영역 중 더 이상 사용하지 않는 영역을
정해진 스케줄에 의해 정리해주는 것을 GC(Garbage Collection)이라 부른다. GC는 Heap 메모리에서 활동하며, JVM에서 GC의 스케줄링을
담당하며 개발자가 직접 관여하지 않아도 더 이상 사용하지 않는 점유된 메모리를 제거해주는 역할을 담당한다.

3. 자바 메모리 구조


  • 가비지 컬렉터(Garbage Collector) :
    -더 이상 참조되지 않는 메모리 객체를 모아 제거하는 역할을 수행
    -일반적으로 자동으로 실행되지만, 수동으로 실행하기 위해 ‘System.gc( )’를 사용할 수 있다.
    런타임 데이터 영역(Runtime data Area)

4. GC의 원리

GC가 가능했던건 ‘약한 세대 가설(weak generational hypothesis)’ 가설 덕분이다.
아래 가정을 기반으로 메모리 구조를 크게 Young Generation, Old Generation으로 물리적 공간을 나눈다.
1 ) 대부분의 객체는 금방 접근 불가능(Unreachable)한 상태가 된다.

  • 대부분의 객체는 중괄호 { } 안에서 생성왼다.
  • 이 객체들은 괄호가 끝나는 시점(메소드, 클래스, 생성자 등)에서 더이상 사용되지 않는다.
  • 특수한 경우에는 오래 사용할 수 있지만, 대부분의 경우 unreachable 한 상태가 되어 GC의 대상이 된다.

2 ) 오래된 객체에서 젊은 객체로의 참조는 아주 적게 발생한다.

  • 일반적으로 순차적인 로직에 의해 객체를 생성하여 활용한다.
  • 이 과정에서 앞에 생성된 객체는 그 다음의 로직에서 사용된 이후 대부분 사용하지 않게 된다.
    (특수한 예외 상황 : 싱글톤 디자인 패턴으로 개발을 하는 경우)
  • 이런 특성으로 인해 더이상 참조되지 않는 객체에 대해 GC를 할 수 있게 되었다.

5. Heap Area

  • Heap 영역 : 동적으로 할당한 메모리 영역으로, 모든 Object(최상위 클래스를 상속받는 모든 데이터) 타입의 데이터가 할당된다. 인스턴스 객체가 생성되는 공간으로, 이 객체가 가리키는 참조변수가 Stack영역에 할당되게 된다.
  • Stack 영역 : 정적으로 할당한 메모리 영역이다. 원시 타입의 데이터가 값과 함께 할당되고, Heap영역에 생성된 Object타입의 데이터의 참조변수를 할당한다.

6. GC 알고리즘

1) Mark- and-Sweep Algorithm
Mark: 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업
Sweep: Mark 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업
Stop The World를 통해 모든 작업을 중단시키면, GC는 스택(자료)의 모든 변수 또는 Reachable 객체를 스캔하면서 각각이 어떤 객체를 참고하고 있는지를 탐색하게 된다. 그리고 사용되고 있는 메모리를 식별하는데, 이러한 과정을 Mark라고 한다. 이후에 Mark가 되지 않은 객체들을 메모리에서 제거하는데, 이러한 과정을 Sweep라고 한다.

2) Mark-and-Compact Algorithm

  • Mark And Sweep 알고리즘과 동일하나 Compact 과정을 한 단계 더 거치게 된다.
  • 그림과 같이 Sweep 이후에 Garbage였던 객체들이 사라지고 남은 빈자리를 남아있는 객체들로 연속된 메모리에 차곡차곡 적재하는 것을 의미한다.
  • Compaction작업을 통해 메모리 공간에 효율을 높일 수 있지만, Compaction 작업 이후 살아남은 객체들의 Reference 하는 작업이 필요하기에 부가적인 오버헤드가 수반된다.
  • 오버헤드란 프로그램의 실행흐름에서 나타나는 현상 중 하나로 프로그램의 실행도중 동떨어진 코드를 실행시켜야 할 때 사용되는 추가적인 시간, 메모리, 자원이 사용되는 현상이다.
  • 예를 들면 10초 걸리는 기능이 간접적인 원인으로 15초가 걸렸다면 오버헤드는 5초인 것이다. *Stop-the-world가 발생하면 오버헤드가 길어지게 된다.

*Stop The world : Garbage Collection는 Garbage Collector가 Heap 영역의 메모리를 JVM이 판단해 더이상 사용되지 않는 인스턴스는 자동으로 할당 된 메모리를 삭제하는 역할을 하는 행위이다.
이렇게 메모리를 복사하고 해제 하는 행위를 실행 하기 위해서는 자바 어플리케이션은 GC를 실행하기 위한 Thread를 제외하고 이외의 모든 Thread는 멈추고 GC가 완료된 이후에나 다시 Thread가 실행 상태로 돌아가게 된다.
이와 같이 이외의 모든 Thread의 작업이 멈추는 상태를 Stop The World라고 하고 어떠한 GC 알고리즘을 사용 하더
라도 Stop The World 상태에 부딪히게 된다. GC 튜닝이라고 하면 이와 같은 Thread의 작업이 멈추는 시간을 최소한으로 줄이는 행위라고 보면 된다.

3) Generational Algorithm
-대부분의 프로그램에서 생성되는 대다수의 객체들이 생성된 지 얼마 되지 않아 Garbage가 되는 짧은 수명을 갖는다는 것과 수명이 긴 몇몇의 객체는 반드시 가지고 있다는 경험을 통해 만들어진 알고리즘이다.
이 알고리즘은 두가지 가정을 전제로 만들어졌다.

  • 대부분의 할당된 객체는 오랫동안 참조 되지 않으며 금방 Garbage의 대상이 된다.
  • 오래된 객체에서 젊은 객체로의 참조는 거의 없다.

6. 7.일반적인 GC과정 (Generational Algorithm)

1.새로 생성된 객체가 Eden 영역에 할당된다. 이 age-bit는 Minor GC에서 살아남을 때마다 1씩 증가하게 된다.

  1. 이 age-bit는 Minor GC에서 살아남을 때마다 1씩 증가하게 된다. 시간이 지나 Heap Area의 Eden 영역에 객체가 다 쌓이게 되면 Minor GC가 한번 일어나게 되고 참조 정도에 따라 Servivor0 영역으로 이동하거나 회수됩니다.

  2. 과정이 반복되다가 Survivor 영역이 가득 차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다. 계속해서 Eden영역에는 신규 객체들이 생성됩니다. 이렇게 또 Eden영역에 객체가 다 쌓이게 되면 Young Generation(Eden+Servivor) 영역에 있는 객체들을 비어있는 Survival인 Survival1 영역에 이동하고 살아남은 모든 객체들은 age가 1씩 증가합니다.

  3. 이러한 과정을 반복하여 계속해서 살아남은 객체는 Old 영역으로 이동(Promotion)된다. 또다시 Eden 영역에 신규 객체들로 가득 차게 되면 다시한번 minor GC가 일어나고 Young Generation (Eden+Servivor) 영역에 있는 객체들을 비어있는 Survival인 Survival0으로 이동시킨 뒤 age를 1 증가시킵니다. 이 과정을 계속 반복합니다.

  1. 객체의 생존 횟수를 카운트하기 위해 Minor GC에서 객체가 살아남은 횟수를 의미하는 age를 Object Header에 기록한다. 그리고 Minor GC 때 Object Header에 기록된 age를 보고 Promotion(이동) 여부를 결정한다. 이 과정을 반복하다 보면 age bit가 특정 숫자 이상으로 되는 경우가 발생합니다. 이때 JVM에서 설정해놓은 *age bit에 도달하게 되면 오랫동안 쓰일 객체라고 판단하고 Old generation 영역으로 이동시킵니다. 이 과정을 프로모션(Promotion)이라고 합니다.

*age bit : Minor GC에서 살아남은 횟수를 기록하는 것

  1. Old generation영역의 메모리를 회수한다. 시간이 지나 Old영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 GC가 실행됩니다. 이렇게 Old generation영역의 메모리를 회수하는 GC를 Major GC라고 합니다.

GC의 종류

  1. Serial GC(java 5,6의 default GC)
  • 가장 단순한 방식의 GC로 싱글 스레드로 동작한다.
  • 싱글 스레드로 동작하여 느리고, 그만큼 Stop-the-world의 시간이 다른 GC에 비해 길다.
  • Mark&Sweep&Compact 알고리즘을 사용한다.
  • CPU가 1개인 경우에만 사용하는 GC이기 때문에 실제론 사용하는 경우가 없다.
  1. Parallel GC(= Throughput Collector)
  • Java 8의 default GC
  • Young 영역에 GC를 멀티 스레드 방식을 사용하기에 앞서 나온 Serial GC에 비해 상대적으로 Stop-the-world의 시간이 짧음
  1. Parallel Old GC
    Parallel GC는 Young영역에서만 멀티 스레드 방식을 사용했다면, Parallel Old GC는
    Old 영역까지 멀티 스레드를 사용한다.

  2. CMS(Concurrent Mark Sweep) GC

  • Stop-the-world로 인하여 Java Application이 멈추는 현상을 줄이고자 만든 GC
  • Rechable한 객체를 한번에 찾지 않고 나눠서 찾는 방식을 사용한다.
  • Initial Mark : GC Root가 참조하는 객체만 마킹(stop-the-world 발생)
  • Concurrent Mark : 참조하는 객체를 따라가며, 지속적으로 마킹.
    (stop-the-world 발생하지않음)
  • Remark : concurrent mark 과정에서 변경된 사항이 없는지 다시 한번 마킹하며 확정하는 과정.(stop-the-world 발생)
  • Concurrent Sweep : 접근할 수 없는 객체를 제거하는 과정(stop-the-world 없이 이루어진다.)

  1. G1(Garbage First) GC
  • Java 9+의 default GC
  • 현재 GC중 가장 stop-the-world의 시간이 짧다.
  • CMS GC를 개선하여 만든 GC이다.
  • Heap을 Region이라는 일정한 부분으로 나눠서 메모리를 관리한다.
  • 전체 Heap를 탐색하지 않고 부분적으로 Region 단위로 탐색하여, 각각의 Region에서만 GC가 발생한다.

  • G1에서 FullGc가 수행되는 과정은
  • Initial Mark -> Root Region Scan -> Concurrent Mark -> Remark -> Cleanup -> Copy 이다.
  • Initial Mark :
  • STW가 발생.
  • Survival 영역에서 Old영역을 참조하고 있을 수 있는 영역들을 찾아 마킹한다.
  • Root Region Scan :
    Initial Mark 단계에서 찾은 Survival Region에 대한 GC대상 객체 스캔작업을 진행.
  • Concurrent Mark
    전체 힙 영역에 대한 스캔으로 살아남은 객체가 존재하는 Region만 식별.
  • Remark
    STW가 발생하며 최종적으로 살아남은 객체를 식별.
  • Cleanup
    STW가 발생하며 살아남은 객체가 가장 적은 Region의 GC대상을 제거 한 뒤 빈 영역을 Available Region으로 변경한다.
  • Copy
    GC대상이었지만 Cleanup 단계에서 완전히 비워지지 않은 지역에 남은 객체를 Available Region으로 복사하여 Compaction을 수행한다.
profile
성장하는 땅콩개발자 :)

0개의 댓글