Garbage Collection ( 쓰레기 수집 )


IT 전공자라면 모두 메모리 관리의 중요성에 대해 한 번쯤은 들어본 적이 있을 것이다.

각종 프로그래밍, 시스템 운용, 여러 프로세스 작업 관리 등 여러 부분에서 메모리를 효율적으로 쓰는 것은

IT 전문가가 되기 위해 기본적으로 갖추어야 될 소양이라고 생각한다.

본 글에서는 이러한 메모리 관리 기법 중 하나인 Garbage Collection에 대해 알아보고자 한다.


 

 Garbage Collection 

  • 동적 할당된 메모리 영역 가운데 더 이상 사용할 수 없게 된 영역을 탐지하여 자동으로 해제하는 기법

  • 사용할 수 없게 된 영역이라 하면, 어떤 변수도 가리키지 않게 된 영역을 의미

  • 주로  Heap 메모리에서 처리 및 사용 여부 식별하고 사용하지 않는 객체는 제거한다.

  • 1959년 리스프의 문제를 해결하기 위해 존 매카시에 의해 개발되었다.


위의 코드에서 for문이 반복될수록 실행문 안의 객체는 새롭게 생성되고

이전의 객체는 Garbage가 되기 때문에 메모리 소모가 늘어나게 된다.

특정 몇몇 언어들의 경우 이러한 메모리 부하 방지를 위해 자동으로 Garbage Collection 기능이

함께 제공되기도 한다.


 

 Garbage Collection 의 장점 


Garbage Collection이 지원되는 환경에서는 프로그래머가 동적 할당 메모리 영역 전체를

완벽하게 관리할 필요가 없어

다음과 같은 버그를 줄이거나 막을 수 있게 된다.


  • 유효하지 않은 포인터 접근
    • 이미 해제된 메모리에 접근하는 버그
    • 해당 포인터가 해제되고, 새로운 값이 할당되면 잘못된 값을 읽어오게 된다.

 

  • 이중 해제
    • 이미 해제된 메모리를 또다시 해제하는 버그
    • 일부 메모리 할당 알고리즘에서 해제된 메모리를 다시 해제하려고 시도하는 경우 오류가 발생할 수 있다.

 

  • 메모리 누수
    • 더 이상 필요치 않은 메모리가 해제되지 않고 남아있는 버그

    • 메모리 누수가 반복되면 메모리 고갈로, 프로그램이 중단될 수 있다.
      (※접근 가능한 메모리 증가로 메모리가 고갈되는 문제는 해결 불가)

 

 

 

 Garbage Collection 의 단점 

  • 해제할 메모리를 결정할 때 비용 발생
    • 객체가 필요없어지는 시점을 알고 있더라도 Garbage Collection 알고리즘에서 메모리 해제 시점을 추적해야 하므로 오버헤드가 된다.

 

  • Garbage Collection이 발생하는 타이밍 및 점유시간 예측 어려움
    • 프로그램이 예측 불가능하게 일시적으로 정지할 수 있기에 실시간 시스템에 적합하지 않다.

 

  • 할당된 메모리가 해제되는 시점 파악 불가
    • 자원 할당과 변수 초기화를 일치시키는 RAII(Resource Acquisition is Intialization) 스타일의 프로그래밍에서는, 자원해제 시점을 알 수 없다는 의미로 본다.

 

 

Garbage Collection 기법은 크게 포인터 추적 방식 참조 횟수 계산 방식으로 나눌 수 있다.

 

 

 

 포인터 추적 방식 


한 개 이상의 변수가 접근 가능한 메모리앞으로 사용할 수 있는 메모리로 간주하고

그 밖의 메모리를 해제하는 방식


 접근 가능한 객체의 재귀적 정의 

  • 어떤 변수가 직접 가리키는 메모리, 또는 간접적으로 가리키는 메모리를 의미

  • 변수가 가리키는 객체. 여기서 변수는 콜 스택에서 정의된 지역 변수와 전역 변수를 모두 포함

  • 접근 가능한 객체가 가리키는 모든 객체는 마찬가지로 접근 가능

 

 여러가지 포인터 추적 기법 

 

1. 표시하고 쓸기 (Mark and Sweep)

 

1) 각 메모리 할당 영역에 표식으로 1비트의 메모리를 남겨놓는다.

2) 표시 단계에서 모든 변수가 가리키는 영역에 "사용 중" 표시

3) 위의 영역에서 가리키는 영역 또한 "사용 중"으로 표시

4) 모든 메모리 영역 표시 후 나머지 영역은 접근 불가능한 메모리 영역으로 간주

5) 접근 불가능 메모리 영역을 쓸기 단계에서 모두 해제

 

※ 단점 

  • 표시 단계에서 메모리 내용이 변경되지 않아야 하기 때문에 전체 시스템 실행 일시 정지
  • 전체 메모리 영역을 검사하므로 메모리 페이징 스타일의 운영체제에서는 프로그램 성능 저하 문제 발생

 

 

2. 삼색 표시 기법

 

각각의 객체를   흰색 ,  회색 ,  검은색 으로 분류하는 기법

 흰색  더이상 접근 불가능한 객체
 회색  접근 가능한 객체, 아직 검사되지 않았음을 의미함
 검은색  객체들이 접근 불가능한 객체(=흰색 객체)를 가리키지 않았음을 뜻함

1) 알고리즘 시작 시 변수가 가리키는 객체들은  흰색 으로 표시, 그 외에는  회색 으로 표시

2)  회색  객체 중 하나를 선택하여  검은색 으로 표시 후 해당 객체가 가리킨 모든 객체 회색 으로 표시

3)  회색  객체가 하나도 남지 않을 때까지 위 과정 반복

4) 남은  흰색  객체는 접근 불가하므로 전부 해제한다.

 

 

3. 객체 이동 기법

  • 해제할 객체를 표시 후, 해제되지 않는 객체를 다른 영역으로 복사하는 기법
  • 재사용 가능 영역사용 중 영역표시할 필요가 없다는 장점이 있다.
  • 할당된 메모리들이 단편화 되는 것을 방지할 수 있다.
  • 연결형 자료구조에서 연결된 객체들이 메모리 상 인접되어 할당될 확률이 높다.

 

4. 세대 단위 기법

  • 각각의 객체를 할당된 시간에 따라 세대별로 구분 후, 각 세대별로 서로 다른 메모리 영역에 객체를 할당하는 방식
  • 한 세대의 메모리 영역이 찼을 시, 메모리 영역에서 살아남은 객체 더 오래된 메모리 영역으로 옮겨진다.
  • 새로 할당된 영역에서는 대부분의 객체가 빠르게 생성 및 해제되고, 오래된 영역에서는 객체의 변화가 적게 이루어짐
  • 메모리의 일부 영역만을 주기적으로 수집하게 되는 특징을 가진 기법

 

 

 

 참조 횟수 계산 방식 


객체에서 참조 횟수를 기억하여, 참조 횟수가 0이 되면 해당 객체를 해제하는 방식

 C++에서는 스마트 포인터라는 특수한 객체를 이용해 이 기법을 구현


 참조 횟수 계산 방식의 장점 

  • 객체가 접근 불가능해지는 즉시 메모리가 해제되어 프로그래머가 객체의 해제 시점을 어느 정도 예측이 가능

  • 객체가 사용된 직후에 메모리를 해제하므로, 메모리 해제 시점에 해당 객체는 캐시에 저장되어 있을 확률이 높다

 

 # 메모리 관리 외에 다른 자원 할당 기법에도 종종 사용되는 방식 


파일시스템의 경우, 하드디스크 블록의 할당과 해제를 담당함에 있어

포인터 추적 방식은 디스크 매체의 특성 상 오랜 시간을 소모하기 때문에

비효율적이나 참조 횟수 계산 방식은 할당된 블록 해제 시점에

해당 블록을 가리키는 포인터가 운영체제의 버퍼에 로딩되어 있어

빠르게 블록을 해제할 수 있어 이 방식을 사용한다.


 

 

 참조 횟수 계산 방식의 단점 

  • 순환 참조로 인한 메모리 누수 발생 가능성
    • 순환 참조란 두 개 이상의 객체가 서로를 가리키고 있을 경우 참조 횟수가 0이 되지 않게 되는 것을 말한다.

 

  • 참조 횟수가 0일 시, 해당 객체가 가리키는 다른 객체들 또한 동시에 0이 되버린다
    • 이 경우, 시간이 과소모 되므로 실시간 시스템에 적합하지 않을 수 있다.

 

 

 

 

 

 

 

참고:

http://minjoon.com/garbage-collection

https://pacs.tistory.com/entry/Garbage-Collection-%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%EC%85%98

https://ko.wikipedia.org/wiki/쓰레기_수집_(컴퓨터_과학)

'Knowledge' 카테고리의 다른 글

도커 ( Docker )  (0) 2019.09.11
파일 시스템  (0) 2019.09.06
JSON (JavaScript Object Notation)  (0) 2019.09.02
XML (eXtensible Markup Language)  (0) 2019.09.01
비밀키 / 공개키  (0) 2019.08.31