충분히 오래 실행하면 시스템의 모든 메모리를 사용하는 장기 실행 스크립트가 있습니다.
스크립트에 대한 자세한 내용을 다루지 않고 두 가지 질문이 있습니다.
- 준수해야 할 "모범 사례"가 있습니까?
- 파이썬에서 메모리 누수를 디버깅하는 기술은 무엇입니까?
__del__
사이클을 제외하고 더 이상 참조되지 않는 메소드가있는 오브젝트를 나열합니다 . 의 문제로 인해주기를 중단 할 수 없습니다 __del__
. 고쳐!
충분히 오래 실행하면 시스템의 모든 메모리를 사용하는 장기 실행 스크립트가 있습니다.
스크립트에 대한 자세한 내용을 다루지 않고 두 가지 질문이 있습니다.
__del__
사이클을 제외하고 더 이상 참조되지 않는 메소드가있는 오브젝트를 나열합니다 . 의 문제로 인해주기를 중단 할 수 없습니다 __del__
. 고쳐!
답변:
이 기사를 살펴보십시오 : 파이썬 메모리 누수 추적
또한 가비지 수집 모듈에는 실제로 디버그 플래그가 설정 될 수 있습니다. 상기 봐 set_debug
기능. 또한, 호출 후 생성 된 객체의 유형을 결정하기 위해 Gnibbler의이 코드를 살펴보십시오 .
이전에 언급 한 대부분의 옵션을 시도했지만이 작고 직관적 인 패키지가 가장 좋습니다 : pympler
가비지 수집되지 않은 객체를 추적하는 것은 매우 간단합니다.이 작은 예를 확인하십시오.
통해 패키지를 설치 pip install pympler
from pympler.tracker import SummaryTracker
tracker = SummaryTracker()
# ... some code you want to investigate ...
tracker.print_diff()
출력에는 추가 된 모든 개체와 소비 한 메모리가 표시됩니다.
샘플 출력 :
types | # objects | total size
====================================== | =========== | ============
list | 1095 | 160.78 KB
str | 1093 | 66.33 KB
int | 120 | 2.81 KB
dict | 3 | 840 B
frame (codename: create_summary) | 1 | 560 B
frame (codename: print_diff) | 1 | 480 B
이 패키지는 더 많은 기능을 제공합니다. 확인 pympler의 문서는 , 특히 섹션은 메모리 누수를 확인 .
pympler
수 있다는 점 은 주목할 가치가 있습니다 . 반 실시간 작업을 수행하는 경우 애플리케이션 성능이 완전히 손상 될 수 있습니다.
Tracemalloc 모듈 은 Python 3.4부터 내장 모듈 로 통합되었으며 이전 버전의 Python에서도 타사 라이브러리 로 사용할 수 있습니다 (테스트하지는 않았습니다).
이 모듈은 가장 많은 메모리를 할당 한 정확한 파일과 라인을 출력 할 수 있습니다. IMHO,이 정보는 각 유형에 할당 된 인스턴스 수보다 무한히 가치가 있습니다 (99 %의 많은 튜플이 생겨 단서이지만 대부분의 경우 거의 도움이되지 않습니다).
pyrasite와 함께 tracemalloc 을 사용하는 것이 좋습니다 . 10 회 중 9 회 , 피라 사이트 쉘 에서 상위 10 개 스 니펫 을 실행하면 10 분 내에 누출을 해결할 수있는 충분한 정보와 힌트가 제공됩니다. 그러나 누출 원인을 여전히 찾을 수 없다면이 스레드에서 언급 한 다른 도구와 함께 pyrasite-shell이 힌트를 줄 것입니다. 또한 pyrasite에서 제공하는 모든 추가 도우미 (예 : 메모리 뷰어)도 살펴 봐야합니다.
전역 또는 정적 데이터 (장기 데이터)를 특별히 살펴 봐야합니다.
이 데이터가 제한없이 커지면 Python에서도 문제가 발생할 수 있습니다.
가비지 수집기는 더 이상 참조되지 않는 데이터 만 수집 할 수 있습니다. 그러나 정적 데이터는 해제해야하는 데이터 요소를 연결할 수 있습니다.
또 다른 문제는 메모리주기 일 수 있지만, 이론적으로 가비지 콜렉터는 최소한 수명이 긴 데이터에 연결되지 않는 한주기를 찾아서 제거해야합니다.
어떤 종류의 장수 데이터가 특별히 귀찮은가? 모든 목록과 사전을 잘 살펴보십시오. 제한없이 커질 수 있습니다. 사전에서는 dicts에 액세스 할 때 문제가 발생하지 않을 수도 있습니다. 사전의 키 수가 눈에 띄지 않을 수 있습니다 ...
프로덕션 환경과 같이 장기 실행 프로세스의 메모리 누수를 감지하고 찾으려면 이제 stackimpact를 사용할 수 있습니다 . 아래에 tracemalloc을 사용합니다 . 이 게시물에 더 많은 정보가 있습니다.
모범 사례에 이르기까지 재귀 함수를 주시하십시오. 제 경우에는 재귀 문제가 발생했습니다 (필요하지 않은 곳). 내가하고있는 일에 대한 간단한 예 :
def my_function():
# lots of memory intensive operations
# like operating on images or huge dictionaries and lists
.....
my_flag = True
if my_flag: # restart the function if a certain flag is true
my_function()
def main():
my_function()
이 재귀 방식으로 작동해도 가비지 수집이 트리거되지 않고 함수의 잔해가 제거되지 않으므로 메모리 사용을 통해 매번 증가하고 증가합니다.
내 해결책은 my_function ()에서 재귀 호출을 꺼내고 다시 호출 할 때 main () 처리하는 것입니다. 이런 식으로 함수가 자연스럽게 끝나고 자체적으로 정리됩니다.
def my_function():
# lots of memory intensive operations
# like operating on images or huge dictionaries and lists
.....
my_flag = True
.....
return my_flag
def main():
result = my_function()
if result:
my_function()
이것은 결코 완전한 조언이 아닙니다. 그러나 미래의 메모리 누수 (루프)를 피할 생각으로 작성할 때 명심해야 할 첫 번째 사항은 콜백에 대한 참조를 허용하는 모든 것이 해당 콜백을 약한 참조로 저장해야한다는 것입니다.