[CS] Garbage Collection 이란?

장준혁·2024년 2월 19일

computer science

목록 보기
1/11
post-thumbnail

💾 Java 의 Garbage Collection

C, C++에서는 개발자가 직접 메모리를 관리해야 한다.

동적 메모리 할당을 위해 malloc() 또는 new를 사용하여 메모리를 할당하고, 더 이상 필요하지 않은 메모리는 free() 또는 delete를 사용하여 해제한다.

이렇게 개발자가 직접 메모리를 관리하면 더 유연한 컨트롤이 가능하지만, 메모리 누수나 해제되지 않은 메모리에 접근하는 등의 문제가 발생할 수 있을 것이다.

처음 C, C++을 통해서 포인터를 배울 때 동적 할당을 하고 종종 할당 해제를 하는 것을 잊어버리곤 했다.
할당 하는 것을 잊어버리지 않기 위해 할당 과 해제 코드를 동시에 적고 진행 했던 기억이 난다.

하지만 Java 의 경우 new로 동적 할당을 하지만 직접 할당 해제를 해 본 적은 없다.

자바에서 할당 해제를 하지 않아도 되는 이유는 뭘까?

🙄 Heap 영역

new 키워드를 사용하여 만든 객체는 모두 힙(Heap) 영역에 할당한다.
기본 데이터 타입의 변수나 함수 내의 지역 변수는 스택(Stack) 영역에 할당한다.

힙 영역은 애플리케이션의 동적 데이터를 저장하는 공간으로, 개발자가 직접 제어할 수 없고 가비지 컬렉터가 관리한다.
JVM(Java Virtual Machine)의 Heap영역은 아래 2가지를 전제로 한다.

  1. 대부분의 객체는 금방 접근 불가능한 상태(Unreachable)가 된다.
  2. 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

Permanent Generation 영역은 Method Area라고도 한다. 객체나 intern된 문자열 정보를 저장하는 곳이다.

힙 영역은 크게 Young 영역과 Old 영역 으로 분리 된다.

📌Young 영역

새롭게 생성된 객체가 할당(Allocation)되는 영역

대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.

Young 영역에 대한 가비지 컬렉션(Garbage Collection)을 Minor GC라고 부른다.

Young 영역은 Eden 영역과 두 개의 Survivor 영역(S0, S1)으로 나눠진다.

  • Eden 영역: 대부분의 객체가 생성되는 곳.
    처음 생성된 객체는 Eden 영역에 할당된다. 이후 Eden영역이 꽉 찬다면 할당이 해제되지 않은 객체를 Servior 영역으로 이동시킨다.

  • Survivor 영역: Eden에서 살아남은 객체들이 이동되는 곳 이다. S0와 S1 중 하나는 항상 비어있어야 하며, 이는 가비지 컬렉션 후 살아남은 객체들이 이동할 공간을 확보하기 위함이다.

📌Old 영역

Young 영역에서 살아남아 특정 횟수 이상 가비지 컬렉션을 거친 객체들이 이동하는 곳 이다.

이 영역에서 가비지 컬렉션이 발생하는 것을 'Major GC'라고 부르며 일반적으로 Major GC는 Young 영역의 가비지 컬렉션보다 시간이 오래 걸린다.

그렇다면 Major GC 는 왜 Minor GC 보다 오래 걸리는 것 일까?

Minor GC 가 상대적으로 느린 이유는 몇 가지 이유가 존재한다.

  • 탐색 대상 객체가 많다 : Old 영역에는 Young 영역보다 훨씬 많은 객체가 있기에 GC가 대상을 찾아내는데 더 많은 시간이 소요됩니다.

  • 복잡한 참조 관계 : Old 영역에는 시스템이 오랫동안 사용해온 객체들이 많이 있다.
    이들 객체는 다른 객체들과 복잡한 참조 관계를 가질 수 있으며, 이러한 참조 관계를 파악하는 것은 상당한 시간이 소요된다.

  • 메모리 정리 : Old 영역에서 객체를 제거한 후에는 메모리를 재구성해야 하는데 시간이 소모 된다.

  • Stop-The-World : 가비지 컬렉션이 일어날 때, JVM은 애플리케이션의 작업을 일시 중지하며 이를 'Stop-The-World'라고 부른다.
    Major GC는 이 시간이 상대적으로 길어, 애플리케이션의 응답 시간에 영향을 줄 수 있다.

🐲 Mark and Sweep

Java에서는 가비지 컬렉션(Garbage Collection, GC)이라는 메커니즘이 메모리 관리를 담당한다.

가비지 컬렉터가 동작하면 Mark and Sweep 알고리즘이 작동을 한다.
Mark 와 Sweep 를 번역하면 알 수 있듯이 Mark 는 표시, Sweep 은 쓸기 의 뜻을 가지고 있다.

📌 Mark

먼저 Root Space로부터 그래프 순회를 통해 연결된 객체들을 찾아내어 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.

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

GC 가 Root 를 돌면서 참조 되고 있는 객체에 표시 를 한다.

📌 Sweep

Mark 과정을 통해서 참조되는 객체들은 전부 표시가 되었다.

만약 영원히 남아있다면 Heap의 한정된 용량이 새로운 객체들의 추가로 인해 점점 부족해질 것이다.

참조되지 않은 객체들을 더 이상의 쓰임이 없다는 뜻이므로 용량을 잡아먹고 있을 이유가 없다.

참조되지 않은 객체들은 전부 제거 함으로써 용량을 확보한다.
이를 Sweep 이라고 명칭 한다.

그렇다면 개발자의 수고를 덜어주는 GC는 단점이 없을까? 라는 의문점이 들었다.

⛔ STW (Stop The World)

GC를 수행하기 위해 JVM이 프로그램 실행을 멈추는 현상.

GC가 작동하는 동안 GC 관련 Thread를 제외한 모든 Thread는 멈추게 되어 서비스 이용에 차질이 생길 수 있다.

서비스를 진행하던 도중 GC가 시작되면 진행 중이던 서비스는 중단되고 GC 가 끝마칠 때까지 대기한다.

만약 GC가 서비스 진행 도중 여러 번 발생한다면 본래 서비스 완료 시간보다 더디게 진행될 것이다.
이는 서비스의 원활한 이용에 차질이 생긴다.

실시간 성이 강조되는 프로그램일 경우 GC에게 메모리를 전담 시키는 것은 맞지 않을 수 있을 것 같다.

📗 정리

프로젝트 기능 구현을 하면서 CS는 평소에 등한시 하는 경향이 있었다.
CS 공부를 하는 시간 보다 기능 구현에 시간을 쏟는 게 의미 있다고 생각했기 때문이다.

물론 기능 구현에 시간을 많이 투자해서 실력적으로 얻은 게 없는 건 아니다.
체감 될 정도로 많은 것을 배웠다고 생각이 된다.

하지만 시간이 지나면 지날수록 기능 구현을 하기 이전에 사용했던 라이브러리, 메모리 관리, 자료구조, 알고리즘 등을 깊게 알지 못하고 가져와서 적용만 한다는 느낌이 조금씩 들었다.

기본적인 CS에 대한 지식이 바탕이 되어야 기능 구현도 순탄하게 할 수 있을 것 같았다.

워낙 CS 공부가 양이 방대 하기 때문에 본인이 사용하는 프로그래밍 언어 및 프레임 워크의 개념부터 천천히 진행해 보는 게 좋을 것 같다.

참고

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

https://velog.io/@mooh2jj/Garbage-Collection%EC%9D%98-Mark-and-Sweep-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98

profile
wkd86591247@gmail.com

0개의 댓글