[Python] GIL(Global Interpreter Lock) 정리
CPython 메모리 관리 방법
CPython
은 reference의 개수를 세는 방법으로 메모리를 관리한다.sys.getrefcount
라는 함수를 이용해서 Python이 세고 있는 객체의 reference 개수를 확인할 수 있다.# 출처: realpython.com >>> import sys >>> a = [] >>> b = a >>> sys.getrefcount(a) 3
a
가 처음 만들어짐 -> reference 1개b
에a
의 reference 할당 -> reference 2개sys.getrefcount
함수에 argument로a
가 들어가서, 이 함수 내부에서a
의 reference 개수를 하나 늘림 -> reference 3개
(함수 종료 시 reference 개수 3 -> 2개로 바뀜)
따라서 최종 출력으로 나오는
a
의 reference 개수는 세 개가 된다. 그리고 이 값이 0이 되면CPython
이 알아서 메모리를 회수한다.
GIL
두 가지를 일단 기억하자
- C에서 쓰레드 사용 시,
race condition
이 일어나지 않도록 하는 것은 사용자의 몫이다. CPython
은 생성되는 개체의 reference를 세어가면서 메모리를 관리한다.
여기서 우리는 CPython
이 reference를 세는 과정에서 문제가 생길 수 있음을 생각해볼 수 있다. 만일 reference를 세는 도중에 race condition
이 발생한다면, 이는 메모리 유실(memory leak)으로 이어질 것이다. (반대로 아직 살아있어야 할 객체를 죽일수도 있다.)
이를 해결하기 위해서는 뮤텍스(mutex)를 이용하면 된다. 그러나 객체마다 뮤텍스를 넣어주는 것은 성능적으로 많은 손해를 불러 일으킨다. 또한 deadlock
이라는 치명적인 위험 상황을 불러들이게 된다.
CPython
의 결정은 이렇다. 뮤텍스를 통해 모든 reference 개수를 일일이 보호하지 말고, Python 인터프리터 자체를 잠그기로 했다. 이거 하나만 뮤텍스로 보호하면 우려하던 문제들이 모두 해결된다. (그러나 이말인 즉슨, 많은 쓰레드를 사용해봤자 오직 한 쓰레드만이 파이썬 코드를 실행할 수 있다는 의미이기도 하다.) 사실상 한 프로세스 안에서 여러 쓰레드를 이용한 병렬 처리를 막은 것이라고도 할 수 있다.
정리하자면 GIL은 인터프리터를 잠그는 락(뮤텍스)이고 이를 사용함으로써 race condition
등의 문제를 해결할 수 있다. 대신 한 쓰레드만이 파이썬 코드를 실행할 수 있다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
[Python] split 함수 (0) | 2021.03.02 |
---|---|
[Python] generator(제너레이터) 정리 (0) | 2021.02.24 |
[Python] bisect (이진 탐색) (0) | 2021.02.04 |
[Python] heapq (최소힙, 최대힙) (0) | 2021.02.03 |
[Python] permutations & combinations (순열과 조합) (0) | 2021.02.02 |