파이썬 메모리 릭 해결을 위한 objgraph 라이브러리
파이썬의 메모리 누수(memory leak)를 그래프 형식으로 표시하고 분석 할 수 있는 라이브러리인 “objgraph”를 소개한다.
1. 설치방법
objgraph를 활용하기 위해서는 xdot, graphviz라이브러리도 같이 설치되어야 한다.
1.1. 설치 라이브러리
콘솔인 경우에는 아래의 명령어를 사용하여 라이브러리를 설치한다.
pip install objgraph
pip install xdot
pip install graphviz
1.2. 설치 확인 방법
아래의 코드를 실행하여 이미지 파일이 정상적으로 생성되는지 확인한다.
x = []
y = [x, [x], dict(x=x)]
import objgraph
objgraph.show_refs([y], filename='sample-graph.png')
1.3. 에러 발생시 대처방법
Image renderer (dot) not found, not doing anything else
- 위의 에러가 발생하면 https://graphviz.gitlab.io/download/ 에 접속하여 ‘ZIP archive for Windows 10’을 다운받아 원하는 위치에 압축을 푼다.
- 그 경로를 환경변수에 넣는다.
- 제어판\시스템 및 보안\시스템 > 고급 시스템 설정 > 고급 > 환경변수 > Path 에 추가
2. 기능 설명
objgraph모듈은 모듈명 의미 그대로 오브젝트들의 그래프를 표현하는 모듈이다.
하지만 의미있는 오브젝트를 선정하여 그래프를 그리기는 쉽지 않다.
이때 의미있는 오브젝트를 잘 선정해야 하는데 하기는
2.1 기본적인 기능
기능 및 함수에 대한 설명을 아래에 간단히 소개하며, 자세한 사항은 공식문서를 참조하면 된다.
https://mg.pov.lt/objgraph/
2.1.1. 가장 많은 인스턴스를 확인
show_most_common_types(limit = '보여줄 인스턴수 개수')
>>> show_most_common_types(limit =10)
function 2118
wrapper_descriptor 1081
dict 1065
tuple 906
method_descriptor 791
builtin_function_or_method 777
weakref 633
getset_descriptor 422
member_descriptor 299
type 188
2.1.2. 인스턴스 목록 확인
상기의 인스턴스 중 상세히 보고 싶은 인스턴스가 있다면 아래의 함수를 활용한다. 리턴값은 오브젝트들의 리스트이다.
예로 ‘type’의 인스턴스를 확인해본다.
objgraph.by_type('인스턴스')
>>> objgraph.by_type('type')
[
<class 'socket._GiveupOnSendfile'>, <class 'socket.socket'>
, ...
]
2.1.3. 오브젝트의 id로 오브젝트 찾기
오브젝트의 id를 알고 있다면 오브젝트를 특정할 수 있다.
objgraph.at(오브젝트 id)
x = []
y = [x, [x], dict(x=x)]
import objgraph
y_id = id(y)
objgraph.show_refs([objgraph.at(y_id)], filename='sample-graph.png')
x = []
y = [x, [x], dict(x=x)]
import objgraph
objgraph.show_refs([y], filename='sample-graph.png')
위의 두 가지 경우의 결과를 보면 같다는 것을 알 수 있다.
2.1.4. 오브젝트의 id리스트로 오브젝트의 리스트 찾기
많은 양의 id리스트를 가지며 매칭되는 오브젝트를 얻을 때 사용한다.
objgraph.at_addrs(오브젝트 id리스트)
x = []
y = [x, [x], dict(x=x)]
import objgraph
id_list = []
id_list.append(id(x))
id_list.append(id(y))
objgraph.show_refs(objgraph.at_addrs(id_list), filename='sample-graph.png')
2.1.5. 새로 생긴 오브젝트 id 취득
어느 특정한 소스 구간에서 생긴 오브젝트의 id를 취득 할때 사용된다.
마지막 함수 호출 이후에 할당된 새 오브젝트를 찾아 id를 표시한다.
objgraph.get_new_ids()
리턴값은 각 오브젝트의 타입과 오브젝트id들로 이루어진 dict형식으로 되어있다.
2.2. API를 활용하여 신규 생성된 오브젝트 그래프 취득
신규 생성된 오브젝트 그래프를 취득하기 위해서는
objgraph.get_new_ids()
함수를 사용한다.
이 함수가 처음 호출되면 모든 오브젝트를 상태에 저장하고 두번째 호출되면 취득한 오브젝트의 id들을 이전의 상태로 옮긴다.
이후 측정하고 싶은 소스코드 이후 다시한번 이 함수를 호출하면 신규 생성된 오브젝트의 id를 취득 할 수 있다.
import objgraph
_ = objgraph.get_new_ids()
_ = objgraph.get_new_ids()
x = []
y = [x, [x], dict(x=x)]
new_ids = objgraph.get_new_ids()
세번째 objgraph.get_new_ids()함수가 실행된 시점의 로그를 보면 아래와 같다.
======================================================================
Type Old_ids Current_ids New_ids Count_Deltas
======================================================================
list 148 151 +3 +3
dict 1051 1052 +1 +1
wrapper_descriptor 1081 1081 +0 +0
weakref 633 633 +0 +0
uname_result 1 1 +0 +0
type 188 188 +0 +0
tuple 623 623 +0 +0
staticmethod 43 43 +0 +0
set 310 310 +0 +0
property 125 125 +0 +0
위의 로그에서 list가 추가되었고 이 부분을 그래프로 나타내고 싶다면 다음과 같은 코드를 넣어 이미지 파일을 취득한다.
new_lists = objgraph.at_addrs(new_ids['list'])
objgraph.show_refs(new_lists, filename='sample-graph.png')
위의 방법을 사용하면 유효한 데이터의 그래프를 취득 할 수 있다.