가비지 콜렉션

2 minute read


기술 면접때, 퀵 정렬에 대하여 물어보았을 때, 제대로 기억이 나지 않아 헛소리 한 경험이 있어, 리마인드 차원에서 요약하려고 한다.

아래는 [나무위키]의 내용 참고자료.

옛날의 언어들은 BASIC처럼 동적인 메모리 할당 기능이 아예 없거나[1] FORTRAN이나 C처럼 프로그래머가 할당한 뒤 수동으로 해제까지 해 줘야 하는 방식이었는데, 사람이 하는 일이 항상 완벽할 수는 없는지라 메모리를 할당해놓고 필요없어진 뒤에도 해제를 안 해서 메모리 누수가 생기거나, 혹은 거꾸로 해제했던 메모리를 실수로 다시 사용하거나, 해제했던 메모리를 또 해제한다거나 하는 온갖 실수가 일어나 수많은 버그가 양산되곤 했다. 이러한 실수는 단순히 프로그램의 논리적 버그나 크래시를 일으키는 수준을 넘어서 수많은 취약점의 온상이기도 하다.[2] 더욱이, 일반적으로 버그는 재현가능하고 오류가 있는 부분으로부터 가까운 곳에서 터져야 잡기 쉬운데, 메모리 관련 버그는 한참 떨어진 곳에서 터지는 데다가 재현불가능한 경우도 있어서 프로그래머에게 지옥같은 디버깅을 선사해준다.

그래서 이러한 문제를 해결하기 위해서 제시된 것이 쓰레기 수집이다. 보통 쓰레기 수집 기능을 채택한 언어의 경우 프로그래머에게 직접적인 메모리 할당과 해제를 하게 하는 대신에 쓰레기 수집기에서 제공하는 할당과 해제를 사용하게 하여 프로그램이 실행되는 중간중간에 쓸모가 없어진 메모리, 즉 쓰레기를 알아서 수집한다.

Tracing Garbage Collection (추적 기반 쓰레기 수집)

Tracing Garbage Collection. 가장 많이 사용되는 쓰레기 수집 기법으로 대부분 경우에 다른 수식어 없이 쓰레기 수집이라고 언급되면 이 방식을 말하는 것이다.

추적 기반이라는 이름답게 프로그램을 실행하다가 특정한 타이밍에 현재 할당된 모든 메모리를 조사하여 그것이 현재 접근 가능한지 불가능한지 분류한 뒤, 접근이 불가능한 메모리를 쓰레기라고 간주하여 해제시키는 방식이다. 보통 항상 접근 가능한 메모리를 root라고 하는데, 여기서부터 검사를 시작하여 메모리가 참조하는 메모리를 확인하는 것을 반복하여 접근 가능/불가능을 나누게 된다.

위 설명 그대로 구현하는 방법 중 naïve mark-and-sweep이 가장 단순한 방식이다. 이 방법은 프로그램 실행 중 적당한 타이밍에 GC를 실행시켜 접근 가능한 메모리에 마킹(mark)을 한 후 마킹이 안 된 메모리는 전부 할당 해제(sweep)하는 방식이다. 이 방식대로면 부가적인 작업 없이도 접근 가능/불가능을 완벽하게 분류해서 해제하는 것이 가능하지만, 중간에 메모리가 변경되면 마킹을 다시 해야하기 때문에 프로그램을 통째로 정지(stop-the-world)시켜야 한다. 이 때문에 이 방식을 채택하면 프로그램이 실행되는 도중에 잠깐 멈추는 시간이 생긴다.

실시간으로 빠르게 동작해야 하는 프로그램에서 뚝뚝 끊기는 것은 큰 단점이다. 그래서 이를 개선하기 위해 한번에 처리하는 대신 조금씩 조금씩 수집을 하거나(점진적), 객체의 사용 시간을 계산해 다른 영역으로 나누어 수집하는 방식(세대별)을 사용하게 된다.

한계

어떤 방식의 쓰레기 수집을 사용하든 실행 시간에 작업을 하는 이상 성능 하락을 피할 수는 없다. 참조 횟수 카운팅 방식은 상시로 성능 저하가 발생하며, 추적 기반 방식은 성능 저하가 발생하는 간격이나 길이를 조절할 수 있을지는 몰라도 성능 저하 자체는 존재한다.

또한 쓰레기 수집기가 존재하더라도 메모리 누수는 발생할 수 있다. 이는 쓰레기 수집기가 더 이상 접근이 불가능한 객체만 회수하기 때문이다. 설령 두 번 다시 사용하지 않는 객체라 할지라도, 프로그래머의 실수로 그 객체로 접근할 수 있는 경로가 하나라도 남게 되면 쓰레기 수집기는 객체를 사용할 가능성이 있다고 판단하고 회수하지 않는다. 게다가 만약 이러한 객체가 프로그램의 실행 도중 계속해서 누적되어 간다면, 프로그램은 메모리 부족으로 결국 뻗고 말 것이다. 이 문제는 근본적으로 쓰레기 수집기가 객체가 계속 사용될지 아닐지 스스로 판단할 수 없기 때문에, 객체에 접근할 수 있는 경로가 있을 경우 무조건 사용하는 객체로 간주해서 발생하는 문제다.[8] 실제로 쓰레기 수집을 제공하는 언어를 사용한다 하더라도, 프로그램이 복잡해질수록 이러한 종류의 메모리 누수가 발생하는 것이 드물지 않다. 쓰레기 수집기가 많은 경우에 알아서 처리하긴 하지만 만능은 아니란 것이다.

참고 사이트

  • https://ko.javascript.info/garbage-collection : 이미지와 javascript 코드 예시를 이용해 매우 자세하고 알기 쉽게 설명해놓은 사이트

Leave a comment