Ruby는 더 이상 참조되지 않는 객체를 회수하는 **가비지 컬렉터(GC)**를 통해 메모리를 자동으로 관리합니다. 현대 Ruby(MRI)는 압축(compaction)을 갖춘 세대별(generational), 점진적(incremental) mark-and-sweep 컬렉터를 사용합니다. 이를 이해하면 성능과 장기 실행 애플리케이션의 메모리 문제 진단에 도움이 됩니다.
자동 가비지 컬렉션
Ruby는 객체를 힙에 할당하고; GC는 더 이상 도달 가능(참조됨)하지 않은 것을 회수함
. 수동으로 메모리를 해제하지 않음.
현대 MRI GC 특성:
✓ Mark-and-sweep — (루트에서) 도달 가능한 객체를 표시, 도달 불가능한 것을 쓸어냄
✓ 세대별 (Ruby 2.1부터) — 새 객체는 자주, 오래된 것은 드물게 수집
("대부분의 객체는 일찍 죽는다"에 기반)
✓ 점진적 — GC 작업을 분산해 일시정지(pause) 시간 감소
✓ 압축 (GC.compact, Ruby 2.7+) — 메모리 단편화 감소
GC는 수동 메모리 관리에서 해방시켜 줍니다. 세대별 접근(어린 객체를 자주 저렴하게, 오래된 것을 드물게 수집)은 효율적으로 만들고, 점진적 수집은 일시정지를 줄입니다.
GC 검사와 튜닝
GC.stat # 상세 GC 통계 (개수, 힙 정보)
GC.start # 수동으로 수집 트리거 (거의 불필요)
GC.compact # 힙 압축 (단편화 감소)
ObjectSpace.count_objects # 타입별 객체 개수 (디버깅)
# 환경 변수 (RUBY_GC_*)로 힙 증가 등을 튜닝
메모리 누수는 여전히 발생함 (GC에도 불구하고)
# GC는 도달 불가능한 객체만 해제 — "누수"는 남아 있는 참조에서 옴:
$global_cache = []
def process(item)
$global_cache << item # ❌ 영원히 증가 — 절대 해제 안 됨 (여전히 참조됨)
end
흔한 Ruby 메모리 증가 원인:
✗ 증가만 하는 전역/클래스 수준 컬렉션 (캐시, 배열)
✗ 장기 생존 객체(상수, 클래스 변수)가 보유한 참조
✗ 클로저/block이 살려두는 큰 객체
→ GC는 도달 가능한 객체를 해제할 수 없으므로, "누수" = 의도치 않게 유지된 참조.
왜 중요한가
Ruby의 메모리 관리와 가비지 컬렉션을 이해하는 것은 귀중한 지식입니다. 특히 메모리 동작이 안정성과 성능에 중요한 장기 실행 Ruby 애플리케이션(Rails 웹 서버, 백그라운드 워커 등)에 그렇습니다.
GC가 수동 메모리 관리에서 해방시켜 주지만(주요 생산성 이점), 어떻게 동작하는지 이해하면 성능 튜닝과 메모리 문제 진단에 도움이 됩니다.
현대 Ruby가 세대별, 점진적, mark-and-sweep 컬렉터를 사용한다는 것(어린 객체를 자주 저렴하게, 오래된 것을 드물게 수집하면서 일시정지를 줄이기 위해 작업을 분산)을 알면 GC 동작과 압박을 추론하는 데 도움이 되며, 과도한 객체 할당이 GC 오버헤드를 증가시킨다는 것(불필요한 할당을 줄이면 성능을 개선할 수 있음)도 알 수 있습니다.
결정적으로, GC에도 불구하고 메모리 누수가 여전히 발생한다는 것 — GC는 도달 불가능한 객체만 해제하므로, "누수"는 의도치 않게 남아 있는 참조(증가만 하는 전역 또는 클래스 수준 컬렉션, 예: 무한정 캐시; 장기 생존 객체가 보유한 참조; 클로저가 살려두는 큰 객체)에서 온다는 것 — 을 이해하는 것은 장기 실행 Ruby 프로세스를 괴롭히는 메모리 증가(실제로 흔한 운영 문제)를 진단하고 고치는 데 중요합니다.
GC의 동작, 검사 방법(GC.stat, ObjectSpace), 튜닝 옵션, 그리고 특히 메모리 증가의 흔한 원인(유지된 참조)을 아는 것은 성능 좋고 안정적인 Ruby 애플리케이션을 운영하는 데 귀중합니다.
Ruby 애플리케이션(특히 Rails 서버)은 장기간 실행되고 유지된 참조로 인한 메모리 누수는 빈번한 실무 문제이므로, Ruby의 GC를 이해하는 것 — 세대별 mark-and-sweep 모델, 도달 가능한 객체를 해제할 수 없다는 것, 메모리 증가의 원인 — 은 성능과 신뢰성을 위한 중요한 시니어 수준 지식이며, 프로덕션 Ruby에서 메모리 문제를 진단하고 고칠 수 있는 개발자를 구별하고 성능 중심 역할에 관련된 주제입니다.
