파이썬 메모리 누수 [폐쇄]


180

충분히 오래 실행하면 시스템의 모든 메모리를 사용하는 장기 실행 스크립트가 있습니다.

스크립트에 대한 자세한 내용을 다루지 않고 두 가지 질문이 있습니다.

  1. 준수해야 할 "모범 사례"가 있습니까?
  2. 파이썬에서 메모리 누수를 디버깅하는 기술은 무엇입니까?

5
내가 발견 한 이 제조법 도움이.
David Schein

유용한 데이터를 너무 많이 인쇄하는 것 같습니다
Casebash

1
@Casebash : 그 함수가 무언가를 인쇄하면 심각하게 잘못하고 있습니다. __del__사이클을 제외하고 더 이상 참조되지 않는 메소드가있는 오브젝트를 나열합니다 . 의 문제로 인해주기를 중단 할 수 없습니다 __del__. 고쳐!
Helmut Grohne

답변:



83

이전에 언급 한 대부분의 옵션을 시도했지만이 작고 직관적 인 패키지가 가장 좋습니다 : 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의 문서는 , 특히 섹션은 메모리 누수를 확인 .


5
SLOW 일pympler 수 있다는 점 은 주목할 가치가 있습니다 . 반 실시간 작업을 수행하는 경우 애플리케이션 성능이 완전히 손상 될 수 있습니다.
가짜 이름

@ sebpiq 이상하게도, 나에게도 마찬가지입니다 ... 이런 일이 일어나고 있는지 전혀 모르 십니까? 소스 코드를 간단히 살펴보면 실제로 통찰력이 없었습니다.
linusg

25

내가 만든 mem_top 도구를 추천하겠습니다

비슷한 문제를 해결하는 데 도움이되었습니다.

파이썬 프로그램에서 메모리 누수의 주요 용의자를 즉시 ​​보여줍니다.


1
그건 사실이지만 ... 사용법 / 결과 설명에 거의 도움이되지 않습니다
me_

@me_,이 도구에는 "사용"및 "결과 설명"섹션이 모두 설명되어 있습니다. "참조는 객체의 참조 횟수, 유형은이 유형의 객체 개수, 바이트는 객체의 크기"와 같은 설명을 추가해야합니까?-이것을 문서화하는 것이 너무 명확하지 않습니까?
Denis Ryzhkov

이 도구의 사용 문서는 "때때로 logging.debug (mem_top ())"라는 단일 행을 제공하지만 결과에 대한 설명은 컨텍스트가없는 저자의 실제 오류 추적 경험입니다. 이는 기술 사양이 아닙니다. 그들이보고있는 정확하게 ... 나는 당신의 대답을 두드리지 않습니다 ... 그것은 높은 수준의 용의자를 청구 한 것으로 보여줍니다 ... 사용 결과를 완전히 이해할 수있는 적절한 문서를 제공하지 않습니다 ... 예를 들어 "결과 설명"출력에서 "GearmanJobRequest"가 명백히 문제인 이유는 무엇입니까? 이유에 대한 설명이 없습니다 ...
me_

1
실수로 도구를 두드리는 것 같아요, 당신은 저자입니다 ... 어떤 범죄도 의도되지 않았습니다 ...
me_

6
@me_, 방금 "Usage"에 다음 단계를 추가하고 "Counters"섹션을 추가했으며, 실제 예제에서 Gearman이 정확히 의심되는 이유를 설명하고 코드에서 "mem_top ()"의 각 선택적 매개 변수를 문서화했습니다. 이 모든 것을 v0.1.7로 업로드했습니다. 다른 개선 사항이 있는지 살펴보십시오. 감사합니다! )
Denis Ryzhkov

18

Tracemalloc 모듈 은 Python 3.4부터 내장 모듈 로 통합되었으며 이전 버전의 Python에서도 타사 라이브러리 로 사용할 수 있습니다 (테스트하지는 않았습니다).

이 모듈은 가장 많은 메모리를 할당 한 정확한 파일과 라인을 출력 할 수 있습니다. IMHO,이 정보는 각 유형에 할당 된 인스턴스 수보다 무한히 가치가 있습니다 (99 %의 많은 튜플이 생겨 단서이지만 대부분의 경우 거의 도움이되지 않습니다).

pyrasite와 함께 tracemalloc 을 사용하는 것이 좋습니다 . 10 회 중 9 회 , 피라 사이트 쉘 에서 상위 10 개 스 니펫 을 실행하면 10 분 내에 누출을 해결할 수있는 충분한 정보와 힌트가 제공됩니다. 그러나 누출 원인을 여전히 찾을 수 없다면이 스레드에서 언급 한 다른 도구와 함께 pyrasite-shell이 ​​힌트를 줄 것입니다. 또한 pyrasite에서 제공하는 모든 추가 도우미 (예 : 메모리 뷰어)도 살펴 봐야합니다.


pytracemalloc.readthedocs.io 는 더 이상 존재하지 않습니다
Dimitrios Mistriotis

12

전역 또는 정적 데이터 (장기 데이터)를 특별히 살펴 봐야합니다.

이 데이터가 제한없이 커지면 Python에서도 문제가 발생할 수 있습니다.

가비지 수집기는 더 이상 참조되지 않는 데이터 만 수집 할 수 있습니다. 그러나 정적 데이터는 해제해야하는 데이터 요소를 연결할 수 있습니다.

또 다른 문제는 메모리주기 일 수 있지만, 이론적으로 가비지 콜렉터는 최소한 수명이 긴 데이터에 연결되지 않는 한주기를 찾아서 제거해야합니다.

어떤 종류의 장수 데이터가 특별히 귀찮은가? 모든 목록과 사전을 잘 살펴보십시오. 제한없이 커질 수 있습니다. 사전에서는 dicts에 액세스 할 때 문제가 발생하지 않을 수도 있습니다. 사전의 키 수가 눈에 띄지 않을 수 있습니다 ...



4

모범 사례에 이르기까지 재귀 함수를 주시하십시오. 제 경우에는 재귀 문제가 발생했습니다 (필요하지 않은 곳). 내가하고있는 일에 대한 간단한 예 :

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()

7
파이썬이 테일 호출을 최적화하지 않기 때문에 재귀 깊이 제한에 도달하면 이러한 방식으로 재귀를 사용하면 중단됩니다. 기본적으로 이것은 1,000 회 재귀 호출입니다.
Lie Ryan

3

파이썬에서 메모리 누수에 대한 "모범 사례"에 대해서는 잘 모르지만 파이썬은 가비지 수집기에서 자체 메모리를 지워야합니다. 그래서 주로 가비지 컬렉터가 선택하지 않기 때문에 짧은 순환 목록을 확인하는 것으로 시작합니다.


3
또는 영원히 보관되는 물체에 대한 언급 등
matt b

3
영원히 보관되는 순환 목록 및 개체의 예를 제공해 주시겠습니까?
Daniel

2

이것은 결코 완전한 조언이 아닙니다. 그러나 미래의 메모리 누수 (루프)를 피할 생각으로 작성할 때 명심해야 할 첫 번째 사항은 콜백에 대한 참조를 허용하는 모든 것이 해당 콜백을 약한 참조로 저장해야한다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.