ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Garbage Collector
    JAVA 2022. 8. 26. 20:57

     

     

    2022.08.26 - [JAVA] - 자바 메모리 구조

     

     

     

    혹시 C, C++를 써본 적이 있다면 메모리를 동적 할당할 때 얼마나 귀찮았는지 알 것이다.

    객체를 생성할 때마다 malloc, new 키워드를 사용해야 하고,

    메모리를 해제하지 않으면 객체가 계속 살아남아 메모리 누수가 일어난다.

     

    이런 불편함을 해결해주는 것이 Garbage Collector이다.

    쓰지 않는 객체는 자동으로 메모리를 해제해서 메모리를 효율적으로 사용할 수 있게 한다.

     

     

     

    즉, 가비지 컬렉터는 이름 그대로 필요없는 객체를 수거하는 역할을 한다.

    그럼 일단 가비지 컬렉터가 어떻게 작동하는지 먼저 알아보자.

     

     

    프로그램이 실행된 후 일정 시간이 지나면 

    모든 스레드를 멈추고(Stop-The-World) 객체를 수거한 후

    프로그램을 다시 작동시킨다.

     

     

    이름과는 다르게 작동 과정의 큰 틀은 어렵지 않다.

    앞으로 설명할 가비지 컬렉팅 방법은 이러한 구성을 따른다.

     

     

    GC 방법을 살펴보기 전에, 만약 위의 글대로 GC가 실행된다면 어떻게 될까?

    모든 스레드가 멈춘다는 말은 곧 프로그램 자체가 멈춘다는 말과 같다.

    몇 분에 한번씩 프로그램이 몇 초 씩 멈춘다면 얼마나 화가 날지 상상할수가 없다.

     

    이러한 상황을 방지하기 위해 다양한 GC 알고리즘을 사용하고 있다.

     

     

     

    이전 글에서 보았던 Heap 영역의 구조를 다시 살펴보자.

     

     

     

     

    객체가 얼마나 오래되었는지에 따라 Young, Old 영역으로 객체가 이동한다고 했다.

     

    굳이 왜 영역을 나누었을까? 그냥 주기적으로 모든 객체를 탐색하면 되지 않을까?

     

     

    조금 생각해보자.

    오래 살아남는 객체가 왜 생길까? 빨리 죽는 객체와 차이점은 뭘까?

     

    가비지 컬렉터는 필요없는 객체를 수거한다고 했다.

    필요없다는 건 참조가 되지 않는 객체를 말한다.

    이는 오래 살아남은 객체는 참조가 되고있다는 것이다.

     

    그렇다면 빨리 죽는 객체는 생긴지 얼마 안 된 객체일 가능성이 높다!

     

     

     

    과정을 자세히 살펴보자.

    객체가 생성되면 Young Generation의 eden 영역에 저장되고, 

    eden 영역이 전부 차게 되면 GC(가비지 컬렉팅)가 일어난다.

     

    여기서 살아남은 객체들은 Survivor영역으로 복사되고,

    Survivor 영역의 두 번의 GC에서도 살아남은 객체들은 Old Generation으로 복사된다.

     

     

    이때 Young 영역에서 일어나는 GC를 Minor GC,

    Old 영역에서 일어나는 GC를 Major GC라 한다.

     

    Minor GC는 속도가 빠른 반면

    Major GC는 참조 관계가 복잡해져 속도가 느려지게 된다.

     

     

     

     

    Serial GC

    Mark Sweep Compact 알고리즘을 사용한다.

    사용되는 객체와 사용되지 않는 객체를 식별(Mark)하고,

    사용되지 않는 객체는 해제(Sweep)하여

    사용되는 객체를 Heap 영역의 앞으로 당겨와서(Compact) 객체가 존재하는 부분과 아닌 부분으로 나눈다.

     

    이 방법은 스레드를 1개만 사용하여 속도가 매우 느리다.

    이를 멀티 스레드로 구현한 방식이 Pararell GC이다.

     

     

     

    CMS(Concurrent Mark Sweep) GC

    이 방식은 프로그램이 실행 중인 동시에 GC가 실행된다.

     

     

     

     

    스레드가 살아있는 객체가 참조중인 객체들을 따라가면서 그 객체들을 Mark하고, 객체들을 Sweep하는데,

    Stop-The-World 하지 않고(Concurrent) GC를 수행한다.

     

    프로그램을 '거의' 멈추지 않고 GC를 수행하기 때문에 반응성이 좋지만

    그만큼 CPU를 많이 사용하게 되고, Compact 작업을 하지 않는다.

     

    따라서 메모리가 조각난 채로 존재하여 마치 메모리 가변 분할 방식의 단점과 같은 문제가 발생한다.

     

    11. 메모리 관리

    오버레이(Overlay) 할당받은 주 기억 장치의 공간보다 프로그램의 용량이 더 클 때 사용하는 방법입니다. 중첩이라 부르기도 합니다. 여러 조각으로 쪼개진 프로그램을 필요한 데이터만 메모리에

    today-studies.tistory.com

     

     

    만약 Compact 작업을 진행하지 않은 채로 GC를 계속 수행하다 보면 

    결국 OutOfMemoryException이 발생하게 될 것이다.

     

     

     

    G1(Garbage First) GC

    CMS GC의 단점을 보완하기 위해 나온 GC 방법으로, 현재까지도 사용되는 GC 방법이다.

     

     

     

    공간을 물리적으로 나누지 않고 균일하게 구역을 분할한 뒤,

    구역을 유동적으로 사용하는 방법이다.

     

    위에서 설명한 GC 알고리즘 중 가장 성능이 뛰어나며, Java9 부터 기본 GC로 사용되고 있다.

     

     

    G1 알고리즘은 위에서 설명한 GC 과정과는 차이가 있다.

     

    Minor GC

    GC는 각 구역의 사용량을 추적하고 있다가 어떤 구역이 객체가 가득 차게 되면(Garbage First),

    그 구역을 Mark and Sweep한다.

     

    Eden 구역에서 GC가 일어나면 Eden은 Available/Unused 상태를 부여받고,

    Available/Unused 구역 중 하나를 Survivor 구역으로 만들어 그곳에 객체를 복사한다.

     

     

    Major GC

    프로그램을 수행하다가 전체적으로 객체가 많아지면 Major GC를 실행하게 된다.

    기존 알고리즘은 Heap의 모든 공간을 탐색, 메모리를 해제했기 때문에 Stop-The-World 시간이 길었다.

     

    G1 알고리즘은 객체가 많은 지역을 알고있어 그 구역의 객체만 메모리를 해제해주면 되기 때문에 훨씬 효율적이며,

    동시에 Concurrent하게 진행되기 때문에 애플리케이션의 지연을 최소화할 수 있다.

     

     

     

     

     

     

    참고 자료

    https://d2.naver.com/helloworld/1329

    https://readystory.tistory.com/48

    https://mangkyu.tistory.com/119

     

     

     

     

    'JAVA' 카테고리의 다른 글

    Call by Value / Reference  (0) 2022.09.01
    자바 메모리 구조  (0) 2022.08.26
    Java Virtual Machine  (0) 2022.08.24

    댓글

Designed by Tistory.