Garbage collection

Ahn9807 (토론 | 기여)님의 2024년 3월 8일 (금) 05:20 판 (새 문서: 분류: 메모리 관리 분류: 소프트웨어 기반 보안 == 개요 == 가비지 컬렉션(GC)은 자동으로 메모리 관리를 해주는 프로그램을 말한다. 가비지 컬렉터는 프로그램에 의해서 할당된 메모리중 더이상 참조되지 않는 메모리를 자동으로 회수한다. 가비지 컬렉션은 프로그래머가 수동 메모리 관리를 수행하는 노력을 덜어주지만, 프로그램의 전체 처리 시간 중 상당한...)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)


개요

가비지 컬렉션(GC)은 자동으로 메모리 관리를 해주는 프로그램을 말한다. 가비지 컬렉터는 프로그램에 의해서 할당된 메모리중 더이상 참조되지 않는 메모리를 자동으로 회수한다. 가비지 컬렉션은 프로그래머가 수동 메모리 관리를 수행하는 노력을 덜어주지만, 프로그램의 전체 처리 시간 중 상당한 부분을 차지할 수 있으며, 결과적으로 성능에 영향을 미칠 수 있다. 네트워크 소켓, 데이터베이스 핸들, 윈도우, 파일 디스크립터 및 장치 디스크립터와 같은 메모리 이외의 리소스는 일반적으로 가비지 컬렉션에 의해 처리되지 않고 다른 방법(예: 디스트럭터)에 의해 처리된다. 이들 테스크는 Latency에 민감하기 때문에 GC를 사용하기에는 무리가 있다.

많은 프로그래밍 언어는 (예: RPL, Java, C#, D,[4] Go 및 대부분의 스크립트 언어)시스템의 일부로 가비지 컬렉션(garbage collection)을 요구하거나 실제 구현을 위해 효과적으로 사용한다. 이러한 언어를 Garbage-collected language라고 한다. C/C++과 같은 일부 언어에서도 GC를 사용하여 메모리 관리를 할 수 있다. 일부 언어에서는 (e.g. D)GC를 기본으로 사용하지만, 속도가 중요할때는 사용자가 수동으로 객체를 삭제하거나 GC를 완전히 비활성화 할 수 있다. 많은 언어에서는 GC에게 힌트를 주기 위해서 free()와 같은 함수를 지원한다.

장단점

장점

GC는 transparently하게 사용자가 메모리를 관리할 수 있도록 한다. 이를 통해서 프로그래머는 다음과 같은 오류를 고민할 필요도 없고, 미연에 방지할 수 있다.

  • Dangling pointer
  • Double-free bug
  • Memory leak
  • Use-after-free

단점

GC는 컴퓨팅 리소스를 사용하여서 동적으로 관리하기 때문에 다음과 같은 문제가 발생한다.

  • 성능상의 오버헤드
  • 추가적인 메모리 사용
  • 예측하거나 감지하기 어려운 성능 & 메모리 오버헤드
  • 일시적인 프로그램의 정지및 예측하기 어려운 정지 시간
  • Latency sensitive한 데이터 베이스, 파일 시스템, 운영체제와 같은 환경에서의 사용할 수 없음

이러한 문제를 해결하기 위해서 다양한 Optimization들이 개발되고 있다.

일반적인 GC동작 방식

Mark and sweep

Tracing을 사용하는 가장 일반적인 방식으로, 루트 객체의 연속적인 참조에 의해서 도달할 수 있는 객체를 추적하여 수집해야 하는 객체를 결정하고 나머지를 Garbage로 간주하는 알고리즘이다. 구현에 사용하는 알고리즘은 여러 종류가 있으며, 성능 특성이 다양하다.

Reference counting

RC는 각 개체에 대해 참조 횟수를 카운트하는 것이다. RC가 0이면 더이상 참조가 없는 Garbager로 간주된다. 개체에 대한 참조가 생성되면 개체의 참조 수가 증가하고 참조가 파괴되면 감소한다. 카운트가 0이 되면 개체의 메모리가 회수된다.

수동 메모리 관리와 마찬가지로 Mark and sweep과는 달리 RC는 개체가 마지막 참조가 파괴되는 즉시 파괴되도록 보장하며, 일반적으로 CPU 캐시에 있는 메모리, 해제할 개체 또는 해당 개체가 직접 가리키는 메모리에만 직접적으로 추적한다. 따라서 CPU 캐시 및 가상 메모리 작업에 큰 부정적인 영향을 미치지 않는 경향이 있다.

그러나 RC도 여러 단점들이 있으며, 이를 최적화 하기 위한 여러 방식들이 개발되고 있다.

  • Cycles: 두개 이상의 개체가 서로를 참조하는 경우, 둘다 수집되지 않는 Cycle를 생성할 수도 있다. 이러한 Cycles들을 추적하기 위해서 일부 GC는 사이클 감시 알고리즘을 사용하여 이 문제를 해결한다. 이 문제를 프로그래밍적으로 해결하는 방법은 Weak pointer를 사용하는 것이다. Weak pointer는 Weak pointer가 가르키는 객체의 RC를 증가시키지 않는 특수 포인터이다. 만약 객체가 쓰레기가 되면, 그 객체에 대한 Weak pointer는 Null pointer를 자동으로 가르키게 되어 안전한 참조가 가능하도록 한다.
  • Memory overhead: 모든 객체에 대한 참조 카운트가 저장될 공간을 할당해야 한다. 따라서 각 객체에 대해서 32비트 혹은 64비트에 해당하는 참조 카운트를 저장할 공간을 할당해야 한다. 이러한 참조 카운트 저장은 추가적인 메모리 오버헤드를 가져온다. 특정 객체지향 언어에서는 (e.g. Object-C)객체에 대한 정보가 저장되는 공간에 참조 카운트를 저장하는 공간으로 re-use해서 메모리 사용에 대한 최적화를 수행하기도 한다.
  • Performance overhead: Reference counting의 수정은 메모리 할당, 객체의 해제에서 추가적인 RC카운트 수정을 필요로 하기 때문에, 성능상의 오버헤드를 일으키기도 한다. 특히 RC에 대한 수정은 Atomic하게 일어나야 하기 때문에 Synchornization을 위한 추가적인 오버헤드가 소요된다. 그러나 일반적으로 RC에 대한 성능상의 오버헤드는 다른 메커니즘에 비해서 저렴한 편이다.

Escape Analsysis

이스케이프 분석은 힙 할당을 스택할당으로 변환시키는 컴파일 타임 기법으로, 이를 통해서 수행해야 하는 가비지 컬렉션의 양을 줄일 수 있다. 이 분석은 함수 내부에 할당된 개체가 함수 외부에서 액세스할 수 있는지 여부를 판단한다. 함수-로컬 할당이 다른 함수 또는 스레드에 액세스할 수 있는 것으로 확인되면 할당은 "탈출"이라고 하며 스택에서 수행할 수 없다. 그렇지 않으면 객체가 스택에 직접 할당되고 함수가 돌아올 때 해제되어 힙 및 관련 메모리 관리 비용을 우회할 수 있다.

GC 최적화

컴파일 타임 분석

컴파일 타임에 프로그램을 분석하여서 알려진 정보로 GC를 최적화 하는 기법이 연구되고 있다. 예를 들어서 LLVM의 Automatic reference counting기법은 Tracing이 아니라 Reference counting방식으로 가비지 컬렉션이 진행될 수 있도록 최적화를 수행한다.

Tracing 최적화

Generational GC
대부분의 객체가 젋은 나이에 죽는다는 관찰을 기반으로, 두개 이상의 할당영역이 유지되면서, 정기적으로 젋은 객체에서 GC가 수행되고 한세대가 가득차면 이전 지역에서 여전히 참조되는 객체를 다음 객체로 옯기고 그 세대를 Free시킨다. 이를 통해서 GC를 수행할 영역을 적응적으로 조정할 수 있다.


같이 보기

  1. Use after free
  2. Mark and sweep