가비지 컬렉터
C언어나 C++등의 Native 언어가 아닌 Java나 C#등의 Managed 언어는 가비지 컬렉터가 있다. 가비지 컬렉터란 말그대로 쓰레기를 수집해주는 녀석이다. 즉, 더이상 참조를 하지않는 메모리(쓰레기)를 자동으로 수집해서 해제해주는 녀석이란 뜻이다. 이러한 가비지 컬렉터는 호출 시점을 프로그래머가 알수 없다. 자동으로 호출되는 구조이기에 가비지 컬렉터로 인한 성능저하를 막기위해서는 가비지(수집될 메모리)를 최대한 만들지 않는게 좋다.
이번에는 가비지 컬렉터에 대해서 알아보려고 한다.(정확히는 C#의 가비지 컬렉터)
가비지 컬렉터는 어떤방식으로 가비지를 수집할까?
- 프로그램에서 더 이상 사용하지 않는 객체를 찾아낸다(세대별로 관리)
- 스택에 힙에 할당된 메모리의 위치를 참조하는 객체인 루트를 할당
- 관리되는 힙의 모든 메모리는 쓰레기라고 가정
- 스택의 루트들을 순회하며 힙에 있는 객체를 참조하는지 조사
- 힙의 객체가 다른 힙의 객체를 참조하는지 여부 또한 조사
- 어떤 루트와 힙의 객체와도 관계없는 객체들은 쓰레기(가비지)로 간주
- 가비지가 사용하는 리소스를 회수한다.
- 회수후 객체 재배치
위에서 세대별로 관리를 한다는 말이 있다. CRL에서 관리하며 세대별로 관리를 한다는게 뭘까? 오래 살아남을 것 같은 객체를 모아놓고 비교적 관심을 덜 주자라는 취지이다. 0~2세대로 관리되며, 관심을 덜준다는건 수집대상에서 제외하자는 것이다. 위에 말했듯이 가비지 컬렉터의 최적화는 가비지를 최대한 만들지 않는것이다.
- 0세대 : 새로 할당된 객체들, 임시 객체
- 가비지 컬렉션이 가장 많이 수행되는 세대이다
- 메모리에서 가장빨리 해제될것 같은 세대
- 임계치에 도달하면 가비지 컬렉션 수행
- 1세대 : 0세대에서 가비지 컬렉션이 일어나고 해제되지 않은 객체들이 승격된 세대
- 1세대 임계치에 도달하면 0~1세대 가비지 컬렉션 수행
- 2세대 : 가장 오래 남아있을것 같은 객체들, 1세대에서 승격
- 2세대에서 임계치에 도달하면 0~2세대 가비지 컬렉션을 수행
- 세대별 임계값(버짓, budget)은 프로세스가 실행됨에 따라 조정됨
가비지 컬렉터를 다루면서 몇가지 주의해야할 사항이 있다.
- 메모리 해제는 자동으로 일어나지만 이는 가비지에 한해서만 이다
- 가비지라고 판단을 못할경우, 해제해야하는 메모리지만 해제하지 못해 메모리 누수가 발생 어디선가 반환되어야 하는 메모리를 의도치 않게 참조하고 있는 경우가 있을수 있다
언제나 느끼지만 메모리관리는 참으로 어려운거 같다…