And Brain said,

Garbage Collector, 프로그램의 스캐빈저 본문

IT/CS

Garbage Collector, 프로그램의 스캐빈저

The Man 2023. 5. 10. 14:31
반응형

 
오늘은 프로그래머의 뒤처리를 담당해 주는 가비지 컬렉터(Garbage Collector, GC)에 대해서 알아보도록 합시다.
 
메모리 관리 방법 중 하나인 가비지 컬렉션(Garbage Collection)은 프로그래머가 동적으로 할당한 메모리 영역 중 사용되지 않는 영역을 자동으로 식별하고 해제하는 기능입니다. 이 개념은 1959년 존 매카시(John McCarthy)가 LISP 언어의 메모리 관리를 위해 처음 도입했다고 알려져 있습니다.
 
과거 프로그래밍 언어들은 동적 메모리 할당 기능이 전혀 없거나, C 계열 언어와 같이 프로그래머가 직접 메모리를 할당한 후 수동으로 해제해야 하는 방식이었습니다. 프로그래머의 메모리 관리가 완벽하지 않을 수 있기 때문에 메모리 누수, 이미 해제된 메모리의 재사용, 해제된 메모리를 다시 해제하는 등의 실수로 인해 많은 버그와 취약점이 발생할 수 있었고 재현불가능한 오류를 발생시키도 하여, 프로그래머들에게 엄청난 디버깅 난이도를 선물했습니다.
 
그리하여 등장한 것이 가비지 컬렉션이라는 개념으로, 프로그래머가 직접 메모리 할당과 해제를 수행하지 않고 가비지 컬렉터가 제공하는 메모리 할당 및 해제 기능을 사용하게 됩니다. 이렇게 해서 프로그램 실행 중 사용되지 않는 메모리, 즉 "가비지"를 자동으로 수집할 수 있게 되었습니다.
 
그럼, 가비지 컬렉션에 대해 더 자세히 알아봅시다.
 
 

참조 카운팅(Reference Counting)

객체에 대한 참조 횟수를 추적하여 메모리 관리를 수행하는 방식으로, 각 객체는 참조 카운터를 가지고 있으며, 객체에 대한 참조가 생성되거나 소멸될 때마다 참조 카운터의 값이 증가하거나 감소하게 됩니다.
 
참조 카운팅의 주요 과정은 아래와 같습니다.

1. 객체 생성: 객체가 생성되면 참조 카운터는 1로 초기화됩니다. 이때 객체는 루트 집합(Root Set)에 속하게 되는데, 루트 집합은 가비지 컬렉션 대상이 아닌 객체들로 구성됩니다.

2. 참조 생성: 객체 A가 객체 B를 참조하게 되면, 객체 B의 참조 카운터가 1 증가합니다.

3. 참조 소멸: 객체 A가 객체 B를 더 이상 참조하지 않게 되면, 객체 B의 참조 카운터가 1 감소합니다.

4. 객체 해제: 객체의 참조 카운터가 0이 되면 해당 객체는 더 이상 참조되지 않는 것으로 판단되어 메모리에서 해제됩니다.

 
이 방식은 객체가 더 이상 필요하지 않을 때 즉시 메모리에서 해제되는 장점이 있습니다. 그러나 참조 카운팅 방식은 순환 참조(Circular Reference) 문제로 인해 가비지를 회수하지 못하는 경우가 발생할 수 있습니다. 순환 참조는 두 개 이상의 객체가 서로를 참조하여 참조 카운터가 0이 되지 않음에도 불구하고, 더 이상 외부에서 그 객체들에 대한 참조가 존재하지 않아 프로그래머가 이 객체들을 직접 조작하거나 사용할 수 없게 됩니다. 즉, 이 객체들은 더 이상 접근할 수 없는 상태가 됩니다.
 
참조 카운팅 방식은 Python, Swift 등에서 사용됩니다.
 
 

트레이싱 기반(Tracing-based)

트레이싱 기반 가비지 컬렉션은 루트 객체로부터 시작하여 참조되는 모든 객체를 탐색하여 접근 가능한 객체를 식별한 다음, 접근할 수 없는 객체를 가비지로 간주하고 메모리에서 해제하는 방법입니다. 이 방법은 참조 카운팅과 달리 순환 참조 문제를 해결할 수 있습니다.
 
트레이싱 기반의 주요 과정은 아래와 같습니다.

1. 루트 객체 식별: 루트 객체는 전역 변수, 스택에 있는 변수, CPU 레지스터에 저장된 객체, 스레드 별 로컬 변수 등 메모리 관리 시스템이 직접 접근할 수 있는 객체들입니다.

2. 객체 탐색 및 마킹: 루트 객체에서 시작하여 참조되는 객체들을 재귀적으로 탐색하며, 방문한 객체에 '마크'를 합니다. 이 과정을 통해 접근 가능한 객체들이 식별됩니다.

3. 가비지 처리: 마킹 과정이 끝난 후, 마크되지 않은 객체들을 메모리에서 해제합니다. 이러한 객체들은 프로그램에서 접근할 수 없는 상태이기 때문에 안전하게 해제할 수 있습니다.

 
트레이싱 기반 가비지 컬렉션의 대표적인 알고리즘 몇 가지만 살펴보도록 합시다.
 
 

마크-앤-스위프(Mark-and-Sweep)

마크-앤-스위프 알고리즘의 가비지 컬렉션 과정은 아래와 같습니다.

마크(Mark) 단계: 이 단계에서 루트 객체(프로그램에서 직접적으로 참조되는 객체)부터 시작하여 참조되는 모든 객체를 탐색하고, 방문한 객체에 표시(Mark)를 합니다. 이 과정은 객체들 간의 참조 관계를 따라가며 이루어집니다.

스위프(Sweep) 단계: 이 단계에서는 메모리 전체를 스캔하면서 마크되지 않은 객체들을 찾아내어 메모리에서 해제합니다. 이렇게 하면 접근할 수 없는 객체들만 메모리에서 제거됩니다.

 

마크-앤-컴팩트(Mark-and-Compact)

마크-앤-컴팩트 알고리즘의 가비지 컬렉션 과정은 아래와 같습니다.

마크(Mark) 단계: 마크-앤-스위프와 동일합니다.

컴팩트(Compact) 단계: 마킹이 끝난 후, 메모리에서 살아있는 객체들을 연속된 영역으로 이동시킵니다. 이 과정에서 메모리 단편화를 줄일 수 있습니다. 이동된 객체들이 차지하는 메모리 영역 이후의 객체들은 가비지로 간주되어 해제됩니다.

 

Copying

Copying 알고리즘의 가비지 컬렉션 과정은 아래와 같습니다.

메모리를 두 개의 동일한 크기의 영역으로 나눈다. (From Space, To Space)
-> 프로그램 실행 중 객체를 From Space에 할당한다.
-> 가비지 컬렉션을 수행할 때 살아있는 객체를 찾는다. (트레이싱)
-> 살아있는 객체들을 To Space로 복사하고, 복사된 객체들의 참조를 업데이트한다.
-> 이제 To Space에 살아있는 객체들이 모두 복사되었으므로, From Space를 비운다. 이때 From Space의 모든 객체는 가비지로 간주되어 메모리가 해제된다.
-> From Space와 To Space의 역할을 바꾸어 새로운 가비지 컬렉션에 대비한다.

 

Generational

Generaltional 알고리즘의 가비지 컬렉션 과정은 아래와 같습니다.

프로그램이 실행되면서 객체가 생성되면, 모든 객체가 젊은 세대에 할당

젊은 세대의 가비지 컬렉션 수행 : 살아있는 객체들만 오래된 세대로 이동(promotion)시키고, 나머지 객체들은 메모리에서 해제한다.

오래된 세대의 가비지 컬렉션 수행 : 살아있는 객체들은 그대로 유지하고, 사용하지 않는 객체들을 메모리에서 해제한다.

정리 및 재활용 : 오래된 세대에서 가비지 컬렉션이 완료되면, 메모리가 정리되고 재활용된다.

 
트레이싱 기반 방식은 Java, Python(참조 카운팅과 트레이싱 기반을 혼용), .NET Framework, Ruby, Go 등의 언어에서 사용됩니다.
 
 

Stop the World !

마지막으로, stop-the-world에 대해 알아봅시다. stw는 보통 가비지 컬렉터가 돌아가는 도중에는 모든 쓰레드들이 중단되고 가비지 컬렉터 쓰레드만 수행하는 것을 뜻하는데, 이에 대해선 다음 포스팅에서 더 자세히 다뤄보도록 합시다.
https://theworldaswillandidea.tistory.com/152

Garbage Collector Stop-The-World(STW), 더 월드!

https://theworldaswillandidea.tistory.com/151 Garbage Collector, 프로그래밍 시스템의 스캐빈저오늘은 프로그래머의 뒤처리를 담당해 주는 가비지 컬렉터(Garbage Collector, GC)에 대해서 알아보도록 합시다. 메모

theworldaswillandidea.tistory.com


 
 
여기까지 가비지 컬렉터에 대해서 간략하게 알아보았습니다. 여러분들이 가비지 컬렉터를 가진 언어를 이용해 대규모 어플리케이션을 다루게 된다면, 이를 알고 계셔야할 것입니다.
이 밖에도 여러 방식의 가비지 컬렉션 방식이 존재하며, 각각의 언어마다 조금씩 다른 방식을 가지고 있으니 더 찾아보시며 공부해보시길 바랍니다.
 

Thanks for watching, Have a nice day.

 

References

https://namu.wiki/w/%EC%93%B0%EB%A0%88%EA%B8%B0%20%EC%88%98%EC%A7%91
https://d2.naver.com/helloworld/1329
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

반응형
Comments