eunsiver·2023년 5월 25일
1

가비지 컬렉션(Garbage Collection)이란?

가비지 컬렉션은 영어로 Garbeage Collection으로 줄여서 GC라고도 부릅니다. 가비지 컬렉션은 자바의 메모리 관리 방법 중의 하나로 JVM의 Heap 영역에서 동적으로 할당했던 메모리 영역 중 필요 없게 된 메모리 영역을 주기적으로 삭제하는 프로세스를 말합니다.

C나 C++에서는 이러한 가비지 컬렉션이 없어 프로그래머가 수동으로 메모리 할당과 해제를 일일이 해줘야 했습니다.

Java는 JVM에 탑재되어 있는 가비지 컬렉터가 메모리 관리를 대행해주기 때문에 개발자 입장에서 메모리 관리, 메모리 누수(Memory Leak) 문제에서 대해 완벽하게 관리하지 않아도 되어 오롯이 개발에만 집중할 수 있다는 장점이 있습니다.


예시를 들자면 다음과 같은 조금 억지스러운(?) 코드를 실행한다고 가정하자.

for (int i = 0; i < 10000; i++) {
  NewObject obj = new NewObject();  
  obj.doSomething();
}

루프문에 의해서 10000 건의 NewObject 객체는 for문 스코프 내에서 생성되고 사용되지만, 루프가 끝나고 루프 밖에서는 더이상 사용할 일이 없어진다.

만일 이런 객체들이 메모리를 계속 점유하고 있다면, 다른 코드를 실행하기 위한 메모리 자원은 지속적으로 줄어들기만 할 것이다. 하지만 우리는 이에 대해서 별다른 작업을 하지 않고 구현 코드를 이어 나간다.

이것이 가능한 이유는, 가비지 컬렉션(GC)이 한번쓰이고 버려지는 객체들을 주기적으로 비워줌으로써 한정된 메모리를 효율적으로 사용할 수 있게 해주기 때문이다.


자바 이외 GC

또한 가비지 컬렉션(GC)는 꼭 자바(Java)에만 있는 개념이 아니다.

파이썬, 자바스크립트, Go 언어 등 많은 프로그래밍 언어에서 가비지 컬렉션이 기본으로 내장되어 있다.

당장 여러분이 보고있는 이 브라우저 역시도 자체적으로 구현된 가비지 컬렉션이 있기 때문에 별다른 메모리 관리 없이 웹페이지를 만들수 있는 것이다.


가비지 컬렉션의 단점

  1. 개발자가 메모리가 언제 해제되는지 정확하게 알 수 없다.

  2. 가비지 컬렉션(GC)이 동작하는 동안에는 다른 동작을 멈추기 때문에 오버헤드가 발생한다.
    (전문 용어로 Stop-The-World)

가비지 컬렉션에는 장점만 있는 것이 아니라 단점도 존재합니다. 대표적으로는 위의 2가지 단점이 존재하는데요. 이 중에서 경우에 따라서 문제가 발생할 수 있는 부분은 GC가 동작하는 동안에는 JVM의 다른 동작들은 잠깐 멈추기 때문에 오버헤드가 발생한다는 점입니다. 이로 인해 GC가 너무 자주 실행되면 소프트웨어 성능 하락의 문제가 되기도 합니다. 이러한 특성으로 인해 실시간으로 계속 동작해주어야 하는 시스템들 예를 들자면 열추적 미사일의 경우에는 잠깐의 소프트웨어 일시정지로도 목표한 결과가 달라질 수 있기 때문에 GC의 사용이 적합하지 않을 수 있습니다.

이로 인해 GC가 너무 자주 실행되면 소프트웨어 성능 하락의 문제가 되기도 하다.

예를들면 익스플로러는 이 가비지 컬렉션를 너무 자주 실행하여 성능 문제를 일으키는 것으로 악명이 높았다.

이런 특성에 따라 실시간 성이 매우 강조되는 포로그램일 경우 가비지 컬렉터(GC)에게 메모리를 맞기는 것은 맞지 않을 수 있다.

따라서 어플리케이션의 사용성을 유지하면서 효율적이게 GC를 실행하는 최적화 작업이 개발자의 숙제가 된다.


가비지 컬렉션의 대상이 되는 객체들

객체들은 실질적으로 Heap영역에서 생성되고 Method Area이나 Stack Area등 Root Area에서는 Heap Area에 생성된 객체의 주소만 참조하는 형식으로 구성됩니다. 하지만 이렇게 생성된 Heap Area의 객체들이 메서드가 끝나는 등의 특정 이벤트들로 인하여 Heap Area 객체의 메모리 주소를 가지고 있는 참조 변수가 삭제되는 현상이 발생하면 위의 그림에서의 빨간색 객체와 같이 Heap영역에서 어디서든 참조하고 있지 않은 객체들이 발생하게 됩니다. 이러한 객체들을 Unreachable하다고 하며 주기적으로 가비지 컬렉터가 제거해줍니다.

Reachable : 객체가 참조되고 있는 상태
Unreachable : 객체가 참조되고 있지 않은 상태 (GC의 대상이 됨)

Mark And Sweep 알고리즘

Mark And Sweep 알고리즘은 가비지 컬렉션이 동작하는 원리로 루트에서부터 해당 객체에 접근 가능한지에 대한 여부를 메모리 해제의 기준으로 삼습니다. Mark And Sweep은 위의 그림과 같이 총 3가지 과정으로 나뉘게 됩니다.

Mark 과정 : 먼저 Root로부터 그래프 순회를 통해 연결된 객체들을 찾아내어 각각 어떤 객체를 잠조하고 있는지 찾아서 마킹합니다.
Sweep 과정 : 참조하고 있지 않은 객체 즉 Unreachable 객체들을 Heap에서 제거합니다.
Compact 과정 : Sweep 후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 압축합니다. (가비지 컬렉터 종류에 따라 하지 않는 경우도 있음)

이렇게 Mark And Sweep 방식을 사용하면 루트로부터 연결이 끊긴 순환 참조되는 객체들을 모두 지울수 있다.

GC의 대상이 되는 Heap 영역

heap 메모리의 구조

JVM의 힙(heap) 영역은 동적으로 레퍼런스 데이터가 저장되는 공간으로서, 가비지 컬렉션에 대상이 되는 공간이다.

Heap영역은 처음 설계될 때 다음의 2가지를 전제 (Weak Generational Hypothesis)로 설계되었다.

  • 대부분의 객체는 금방 접근 불가능한 상태(Unreachable)가 된다.

  • 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.
    즉, 객체는 대부분 일회성되며, 메모리에 오랫동안 남아있는 경우는 드물다는 것이다.

이러한 특성을 이용해 JVM 개발자들은 보다 효율적인 메모리 관리를 위해, 객체의 생존 기간에 따라 물리적인 Heap 영역을 나누게 되었고 Young 과 Old 총 2가지 영역으로 설계하였다

Young 영역(Young Generation)

새롭게 생성된 객체가 할당(Allocation)되는 영역
대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
Young 영역에 대한 가비지 컬렉션(Garbage Collection)을 Minor GC라고 부른다.

Old 영역(Old Generation)

Young영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
Old 영역에 대한 가비지 컬렉션(Garbage Collection)을 Major GC 또는 Full GC라고 부른다.

위 그림에서, Old 영역이 Young 영역보다 크게 할당되는 이유는 Young 영역의 수명이 짧은 객체들은 큰 공간을 필요로 하지 않으며 큰 객체들은 Young 영역이 아니라 바로 Old 영역에 할당되기 때문이다.

Heap Area는 효율적인 GC를 위해 위와 같이 Eden, Survival, Old Generation으로 나뉩니다.

Eden

new를 통해 새로 생성된 객체가 위치.
정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor 영역으로 보냄

Survivor 0 / Survivor 1

최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
Survivor 영역에는 특별한 규칙이 있는데, Survivor 0 또는 Survivor 1 둘 중 하나에는 꼭 비어 있어야 하는 것이다.

가비지 컬렉션 동작 과정

첫 번째 과정

객체가 처음 생성되고 Heap영역의 Eden에 age-bit 0으로 할당됩니다. 이 age-bit는 Minor GC에서 살아남을 때마다 1씩 증가하게 됩니다.

두 번째 과정

시간이 지나 Heap Area의 Eden 영역에 객체가 다 쌓이게 되면 Minor GC가 한번 일어나게 되고 참조 정도에 따라 Servivor0 영역으로 이동하거나 회수됩니다.

세 번째 과정

계속해서 Eden영역에는 신규 객체들이 생성됩니다. 이렇게 또 Eden영역에 객체가 다 쌓이게 되면 Young Generation(Eden+Servivor) 영역에 있는 객체들을 비어있는 Survival인 Survival1 영역에 이동하고 살아남은 모든 객체들은 age가 1씩 증가합니다.

네 번째 과정

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

다섯 번째 과정

이 과정을 반복하다 보면 age bit가 특정 숫자 이상으로 되는 경우가 발생합니다. 이때 JVM에서 설정해놓은 age bit에 도달하게 되면 오랫동안 쓰일 객체라고 판단하고 Old generation 영역으로 이동시킵니다. 이 과정을 프로모션(Promotion)이라고 합니다.

마지막 과정

시간이 지나 Old영역에 할당된 메모리가 허용치를 넘게 되면, Old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 GC가 실행됩니다. 이렇게 Old generation영역의 메모리를 회수하는 GC를 Major GC라고 합니다. Major GC는 시간이 오래 걸리는 작업이고 이때 GC를 실행하는 스레드를 제외한 모든 스레드는 작업을 멈추게 됩니다. 이를 'Stop-the-World' 라 합니다. 이 작업이 너무 잦으면 프로그램 성능에 문제가 될 수 있습니다.

업로드중..


참고
https://coding-factory.tistory.com/829

https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%EC%85%98GC-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC

profile
Let's study!

0개의 댓글