Garbage collection과 memory leak

Garbage collection(a.k.a. GC)은 프로그램이 더 이상 접근할 수 없는 메모리를 자동으로 해제시켜 주는 기술을 의미한다. John McCarthy가 Lisp에 처음 구현한 이후 많은 언어가 사용하여 현대 프로그래머 중에 모르는 사람이 없다고 해도 좋을 정도로 널리 알려진 개념이다. 근데 이 GC에 대해서 사람들이 자주 착각하는 것이 있다. GC를 사용하는 이유가 memory leak을 잡아주기 위해서라고 생각하는 것이다. 만약 이렇게 생각했다면 GC에 대해 큰 착각을 하는 것이다.

GC는 memory leak을 막지 못한다. 사실 튜링 완전한 언어에서 memory leak을 막아주는 방법은 세상에 존재할 수 없다. 이것을 설명하기 위해서는 우선 memory leak이 무엇인지 알아야 한다. Wikipedia는 memory leak을 다음과 같이 설명한다.

a type of resource leak that occurs when a computer program incorrectly manages memory allocations in such a way that memory which is no longer needed is not released.

쉽게 설명해 memory leak이란, 사용하지 않을 메모리를 해제하지 않는 현상이다. 결국 memory leak을 잡기 위해서는 사용하지 않는 메모리를 찾아내는 것이 먼저다. 그리고 사용하지 않는 메모리를 완벽하게 찾아내는 건 불가능하다. 자세한 설명은 아래 코드를 통해서 하도록 하겠다.

위 코드에서 x는 언제 해제해야 할까? 보통은 use(x)가 끝난 뒤 해제해야 한다고 생각할 것이다. 하지만 some_function이 종료되지 않는 함수라면 어떨까? some_function이 내부에서 무한 루프를 돌고 절대 종료되지 않는 함수라면 use(x)는 호출될 일이 없다. 따라서 x는 앞으로 접근할 일이 없는 메모리고, some_function이 실행되고 있는 동안 x를 해제하지 않고 있는 것은 memory leak이다. 따라서 이 함수가 memory leak이 없다고 하려면 some_function이 실행되기 전에 이 함수가 종료되는 함수인지 아닌지 분석해서 x의 메모리 해제 시점을 결정해야 한다. 어떤 함수를 실행하기 전에 종료되는지 알 수 있다는 것은 정지 문제를 풀 수 있다는 것이므로 모순이다. 따라서 실행 전에 some_function이 종료되는지 알 방법은 없다. 즉, memory leak을 완벽히 잡는 방법은 존재할 수 없다.

그래서 GC를 비롯한 메모리 관리 기술들은 전부 앞으로 사용하지 않는 메모리를 전부 해제하는 것을 보장하지 않는다. 대신 앞으로 사용하지 않는 것이 확실한 메모리만 해제하는 방식으로 동작한다. 즉, memory leak을 모두 잡는 대신 해제해도 안전한 메모리만 해제하는 것이다. 이를 조금 더 formal 하게 표현하면, '이 메모리를 해제해도 안전한가?'라는 질문에 completeness는 포기하지만, soundness를 보장하는 알고리즘으로 해제할 메모리를 찾는다고 할 수 있다.

모든 memory leak을 잡지는 못하지만, 해제해도 안전한 메모리만을 해제하는 것. 이것이 GC의 역할이다. GC를 사용하면 사용해야 할 메모리를 해제하지 않는다. 즉, dangling pointer가 생기지 않는다는 것이고, 이에 따라서 double free나 use-after-free 같은 문제가 생기지 않는다. 즉, GC는 메모리 사용의 효율성이 아닌, 소프트웨어의 안정성을 올리는 도구라는 것이다.

GC를 썼더니 결과적으로 memory leak이 줄었다는 일은 있을 수 있다. 하지만 memory leak을 잡기 위해 GC가 있는 언어를 선택한다거나, GC가 있는 언어를 쓴다고 memory leak이 없을 것이라 생각하면 안 된다. 아쉽게도 memory leak은 사람이 소스를 분석해서 잡는 수밖에 없다. GC를 비롯한 메모리 관리 시스템은 전부 memory leak을 잡기 위한 기술이 아니라 해제해도 안전한 메모리만 해제하기 위한 기술로써 사용해야 한다.

댓글

이 블로그의 인기 게시물

[C++] enum class - 안전하고 쓰기 쉬운 enum

Log Aggregator 비교 - Scribe, Flume, Fluentd, logstash

RAII는 무엇인가

[Python] cache 데코레이터로 최적화하기

[Web] SpeechSynthesis - TTS API