- 파이썬은 레퍼런스 카운팅 방식으로 가비지 컬렉션을 수행해 메모리를 관리한다는 것을 보고 정리해본다.
- GC는 메모리 관리 기법 중의 하나로 동적으로 할당된 메모리 영역 가운데 더이상 사용할 수 없게 된 영역, 즉 어떠한 변수도 가리키지 않게 된 영역을 탐지하여 해제하는 역할을 한다.
- GC의 장점
1) 유효하지 않은 포인터 접근 방지 : 이미 해제가 된 메모리 영역에 접근하는것을 방지한다.
2) 이중 해제 방지 : 이미 해제된 메모리를 다시 해제하는 버그 방지
3) 메모리 누수 방지 : 더 이상 필요하지 않은 메모리가 해제되지 않고 계속 메모리에 남아있는 버그 방지 (이 현상이 심해지면 메모리 고갈로 프로그램 강제 종료 가능)
- GC 단점
1) 어떤 메모리를 해제하고 언제 해제할지 결정해야 하고 이에 대한 메모리가 소요된다.
2) GC를 언제 실행시킬지 예측이 어렵다.
3) 할당된 메모리가 해제되는 시점을 알 수 없다.
- 파이썬의 GC
~ 파이썬은 기본적으로 GC가 돌아가며 메모리를 관리한다. 그리고 추가로 gc모듈을 통해 직접 제어도 할 수 있긴 하다.
~ 이 때 어떤 기준으로 파이썬 내부적으로 GC가 돌아갈까
- generation과 threshold로 가비지 컬렉션의 주기와 객체를 관리하고 있다. generation, 세대는 0세대, 1세대, 2세대로 구분되며 오래된 객체일 수록 세대 숫자가 높아진다. (하나의 객체는 하나의 세대에만 속할 수 있다.) 그리고 세대가 낮을 수록 자주 GC를 해준다. 그리고 threshold는 주기를 관리해준다. (generation : GC 대상 객체 관리 / threshold : GC 주기 관리)
- 아래 예시 기준으로 1세대의 threshold는 700번, 2세대는 10, 3세대는 10으로 해당 세대의 객체가 생성되면 +1, 해제되면 -1을 한다. 그리고 값이 threshold을 초과하면 0으로 리셋해주면서 그 윗세대의 값을 +1해주고 해당 세대에 대한 GC를 실시한다.
요약하면,
메모리 할당이 이루어 지면 generation[0].count++, 해제시 generation[0].count--가 발생하고,
generation[0].count > threshold[0]이면 genereation[0].count = 0, generation[1].count++이 발생하고
generation[1].count > 10일 때 0세대, 1세대 count를 0으로 만들고 generation[2].count++을 한다는 뜻이다.
- threshold 기준으로 GC가 이루어질 때 내부적으로 collect()함수가 실행되고 이 함수안에서는 unreachable, 즉 도달할 수 없는 고립된 값을 찾아낸다. 이때 reachable값으로 인식된 객체들은 상위 세대로 이동시키고, unreachable 객체로 판단된 메모리는 콜백을 수행한 후 메모리에서 해제된다.
- 레퍼런스 카운팅 방식
~ 그럼 이제 GC 방식중에 하나인 레퍼런스 카운팅 방식이란, 하나의 객체가 참조되면 참조값을 1 늘린다. 이러한 방식으로 참조값이 0인 객체는 참조되는 것이 하나도 없으므로 유효한 객체라 보지않고 메모리에서 삭제한다.
~ 단점은 많은 수의 단위 객체를 참조하면 전부 참조값을 조회해야하므로 속도 저하가 발생할 수 있으며 서로 참조하게 되면 순환 참조 오류가 발생하여 참조 파괴가 잘못 발생하거나 객체 고아가 될 수 있다.
- 이로써 Python 내에서 메모리 관리하는 것에 대해 알아보았고 기본적으로 수행하는 GC를 맹신하면 안되는 이유에 대해서는 다른 포스팅에서 다뤄보겠움
'Backend 언어 > Python Django' 카테고리의 다른 글
GC, 그대로 두면 아니되는 이유 (0) | 2020.02.17 |
---|