Programming language/C#

[C#]가비지 컬렉터(Garbage collector)

CodingGom 2022. 4. 12. 22:55

이 글은 이전에 운영하던 깃 블로그에서 옮겨온 글입니다.

 

서론

예전 글 중에 [Android] 가비지 컬렉터(Garbage collector)에 관한 글을 쓴 적이 있습니다. Java와 같은 Managed 언어인 C#에서도 메모리 관리를 도와주는 가비지 컬렉터가 존재하는데요. Android 가비지 컬렉터와는 어떤 게 다른 것인지, 알아보고자 합니다. 가비지가 무엇인지, 컬렉터는 무슨 일을 하는 녀석인지 등은 동일하기에 별도로 다루지 않고, C#의 가비지 컬렉터는 가비지 수집을 어떻게 하는지 방식 위주로 다뤄보려 합니다.


C# 가비지 컬렉터의 컬렉션 방식

C#(. Net환경)의 가비지 컬렉터는 어떤 방식으로 가비지를 수집할까요? 아래 설명은 가비지를 판단하고 회수하는 법에 관한 간단한 설명입니다.

  • 프로그램에서 더 이상 사용하지 않는 객체를 찾아냄(세대별로 관리)
    • 스택에 힙에 할당된 메모리의 위치를 참조하는 객체인 루트를 할당
    • 관리되는 힙의 모든 메모리는 쓰레기라고 가정
    • 스택의 루트들을 순회하며 힙에 있는 객체를 참조하는지 조사
    • 힙의 객체가 다른 힙의 객체를 참조하는지 여부 또한 조사
    • 어떤 루트와 힙의 객체와도 관계없는 객체들은 쓰레기(가비지)로 간주
  • 가비지가 사용하는 리소스를 회수(메모리 회수)
  • 회수 후 객체 재배치

 위에서 세대별로 관리를 한다는 말이 있습니다. CLR에서 관리하며 세대별로 관리를 한다는 게 뭘까? 오래 살아남을 것 같은 객체를 모아놓고 비교적 관심을 덜 주자라는 취지이다. 0~2세대로 관리되며, 관심을 덜 준다는 건 수집대상에서 제외하자는 것이다. 위에 말했듯이 가비지 컬렉터의 최적화는 가비지를 최대한 만들지 않는 것입니다.

  • 0세대 : 새로 할당된 객체들, 임시 객체
    • 가비지 컬렉션이 가장 많이 수행되는 세대
    • 메모리에서 가장 빨리 해제될 것 같은 세대
    • 임계치에 도달하면 가비지 컬렉션 수행
  • 1세대 : 0세대에서 가비지 컬렉션이 일어나고 해제되지 않은 객체들이 승격된 세대
    • 1세대 임계치에 도달하면 0~1세대 가비지 컬렉션 수행
  • 2세대 : 가장 오래 남아있을 것 같은 객체들, 1세대에서 승격
    • 2세대에서 임계치에 도달하면 0~2세대 가비지 컬렉션을 수행
  • 세대별 임계값(버짓, budget)은 프로세스가 실행됨에 따라 조정됨

가비지 컬렉터를 다루면서 몇 가지 주의해야 할 사항이 있습니다.

  • 메모리 해제는 자동으로 일어나지만 이는 가비지에 한정
  • 가비지라고 판단을 못할 경우, 해제해야 하는 메모리지만 해제하지 못해 메모리 누수가 발생 어디선가 반환되어야 하는 메모리를 의도치 않게 참조하고 있는 경우일 수 있음

언제나 느끼지만 메모리 관리는 참으로 어려운 거 같습니다. 직접 관리하는 것이나, 관리자가 따로 있어 어떻게 하면 더 잘 관리하게 해 주고, 비용을 줄일지 등…


마무리

 사실 가비지 컬렉터의 활동은 자동으로 일어납니다. 아무리 성능 부하가 일어난다 하더라도, 이 기능을 없앨 수는 없죠. 없애면 메모리 관리에 관한 수고가 추가되니 메모리 누수 등 문제를 직접 해결해야 하기 때문이죠. 성능 부하가 생기는데 어쩌죠?라는 의문이 생길 수 있지만... 사실 가비지를 줄여주는 게 최선이 아닐까 싶습니다.

반응형
LIST