2009-08-27 5 views
24

저는 장고에서 실행되는 작은 멀티 스레드 스크립트를 가지고 있으며 점점 더 많은 메모리를 사용하기 시작합니다. 하루 종일 놔두면 약 6GB의 RAM을 먹어서 교환을 시작합니다.파이썬 : 메모리 누수 디버깅

http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks에 따라 내가 (사용 된 메모리의 800M와) 가장 일반적인 유형으로 이것을 참조 :

(Pdb) objgraph.show_most_common_types(limit=20) 
dict      43065 
tuple      28274 
function     7335 
list      6157 
NavigableString   3479 
instance     2454 
cell      1256 
weakref     974 
wrapper_descriptor   836 
builtin_function_or_method 766 
type      742 
getset_descriptor   562 
module      423 
method_descriptor   373 
classobj     256 
instancemethod    255 
member_descriptor   218 
property     185 
Comment     183 
__proxy__     155 

이상한 아무것도 표시되지 않습니다. 메모리 문제를 디버그하는 데 도움이되도록 지금해야 할 일은 무엇입니까?

업데이트 : 사람들이 추천하는 몇 가지 시도. 나는 밤새 프로그램을 운영했고, 내가 일하면 50 % * 8G == 4G RAM을 사용했다.

(Pdb) from pympler import muppy 
(Pdb) muppy.print_summary() 
            types | # objects | total size 
========================================== | =========== | ============ 
            unicode |  210997 |  97.64 MB 
             list |  1547 |  88.29 MB 
             dict |  41630 |  13.21 MB 
             set |   50 |  8.02 MB 
             str |  109360 |  7.11 MB 
            tuple |  27898 |  2.29 MB 
             code |  6907 |  1.16 MB 
             type |   760 | 653.12 KB 
            weakref |  1014 |  87.14 KB 
             int |  3552 |  83.25 KB 
        function (__wrapper__) |   702 |  82.27 KB 
         wrapper_descriptor |   998 |  77.97 KB 
             cell |  1357 |  74.21 KB 
    <class 'pympler.asizeof.asizeof._Claskey |  1113 |  69.56 KB 
         function (__init__) |   574 |  67.27 KB 

이는 4G에 합산되지 않으며, 실제로 큰 데이터가 수정되도록 구성되지 않습니다. 유니 코드는 "완료"노드의 집합()에서 가져온 것이고 목록의 모양은 임의로 weakref과 같습니다.

저는 G extension을 필요로했기 때문에 guppy를 사용하지 않았고 root를 가지고 있지 않았기 때문에 빌드하는 데 어려움이있었습니다.

내가 사용하고있는 object 중 __del__ 메소드를 가지고 있지 않으며 라이브러리를 살펴보면 django 나 python-mysqldb처럼 보이지 않습니다. 다른 아이디어?

+0

"장고에서 실행 중"? 비 웹 서비스 백그라운드 처리를 수행하기 위해 장고 웹 서버를 사용하고 있다는 것을 의미합니까? 이 웹 이외의 것들을 별도의 프로세스로 분리하는 것을 고려 했습니까? –

+2

Django settgings.py를 가져오고 장고 ORM 기능을 많이 사용하는 cron 작업입니다. 그래서, 그것은 웹 서버에 의해 산란되지는 않지만 여전히 관련이있을 수있는 많은 기능을 사용합니다 –

답변

31

http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/을 참조하십시오. 짧은 대답 : django를 실행하고 있지만 웹 요청 기반 형식이 아닌 경우 수동으로 db.reset_queries()을 실행해야합니다. 물론 다른 사람이 언급했듯이 DEBUG = False 여야합니다. Django는 웹 요청 후 자동으로 reset_queries()을 처리하지만 사용자의 형식으로는 절대로 발생하지 않습니다.

+2

db.reset_queries()가 문제를 해결했습니다. 대단히 감사합니다. – pyeleven

0

시도 Guppy

기본적으로 더 많은 정보가 필요하거나 일부 정보를 추출 할 수 있어야합니다. Guppy는 데이터의 그래픽 표현도 제공합니다.

1

다른 도구를 사용해야한다고 생각합니다. 분명히, 당신이 가진 통계는 단지 GC 객체 (사이클에 참여할 수있는 객체)에 관한 것입니다. 가장 주목할 만하게, 그것은 끈이 없다.

Pympler을 사용하는 것이 좋습니다. 이것은 더 상세한 통계를 제공해야합니다.

+0

상단은 7 % * 8GB = 560M을 사용하는 내 앱을 보여줍니다. pympler.muppy.print_summary()는 약 55M을 보여줍니다. 나머지는 어디 있습니까? –

6

gc.set_debug()을 사용해 보셨습니까?

당신은 자신에게 간단한 질문을해야합니다

  • 내가 __del__ 방법으로 개체를 사용하고 있습니까? 나는 절대적으로 그것을 분명히 필요로 하는가?
  • 코드에서 참조주기를 얻을 수 있습니까? 물건을 없애기 전에이 서클들을 깨뜨릴 수는 없나요?

    import gc 
    
    class A(object): 
        def __del__(self): 
         print 'a deleted' 
         if hasattr(self, 'b'): 
          delattr(self, 'b') 
    
    class B(object): 
        def __init__(self, a): 
         self.a = a 
        def __del__(self): 
         print 'b deleted' 
         del self.a 
    
    
    def createcycle(): 
        a = A() 
        b = B(a) 
        a.b = b 
        return a, b 
    
    gc.set_debug(gc.DEBUG_LEAK) 
    
    a, b = createcycle() 
    
    # remove references 
    del a, b 
    
    # prints: 
    ## gc: uncollectable <A 0x...> 
    ## gc: uncollectable <B 0x...> 
    ## gc: uncollectable <dict 0x...> 
    ## gc: uncollectable <dict 0x...> 
    gc.collect() 
    
    # to solve this we break explicitely the cycles: 
    a, b = createcycle() 
    del a.b 
    
    del a, b 
    
    # objects are removed correctly: 
    ## a deleted 
    ## b deleted 
    gc.collect() 
    

    난 정말 응용 프로그램에서 순환되는 플래그 개체/개념을 격려하고 자신의 일생에 초점을 맞출 것이다 :

참조는, 주요 문제는 __del__ 방법을 포함하는 객체의주기 될 것이다 : 더 이상 필요하지 않으면 참조할만한 것이 있습니까?당신은 당신이 당신이 필요로하는 경우에만 실제 데이터를 유지하는 것이 조심, "볼"-like 사전, 또는 역사를 사용해야하는 경우

import gc 

# class without destructor 
class A(object): pass 

def createcycle(): 
    # a -> b -> c 
    #^  | 
    # ^<--<--<--| 
    a = A() 
    b = A() 
    a.next = b 
    c = A() 
    b.next = c 
    c.next = a 
    return a, b, b 

gc.set_debug(gc.DEBUG_LEAK) 

a, b, c = createcycle() 
# since we have no __del__ methods, gc is able to collect the cycle: 

del a, b, c 
# no panic message, everything is collectable: 
##gc: collectable <A 0x...> 
##gc: collectable <A 0x...> 
##gc: collectable <dict 0x...> 
##gc: collectable <A 0x...> 
##gc: collectable <dict 0x...> 
##gc: collectable <dict 0x...> 
gc.collect() 

a, b, c = createcycle() 

# but as long as we keep an exterior ref to the cycle...: 
seen = dict() 
seen[a] = True 

# delete the cycle 
del a, b, c 
# nothing is collected 
gc.collect() 

: 심지어 사이클

__del__없는 방법, 우리는 문제를 가질 수 있습니다 외부 참조가 없습니다.

나는 실망 스럽지만 이제는 set_debug입니다. 데이터를 stderr가 아닌 다른 곳으로 출력하도록 설정 되었으면 좋겠지 만, that should change soon 일을 바랍니다.

+0

gc.collect()는 모든 것을 collectible로 반환하고 두 번째 호출에서 0을 반환합니다. 즉, 사이클이 올바르지 않다는 뜻입니까? –

+0

@Paul : 아니요,주기가 계속 남아 있습니다. 마지막 예제를 보자. gc.collect()는 0을 반환하고 아무 것도 출력되지 않는다. __del__ 메쏘드가없는 객체 사이클을 가지고 있다면, gc는 조용하게있을 것입니다. – NicDumZ

1

확장 프로그램을 사용하고 있습니까? 그들은 메모리 누출을위한 멋진 장소이며, 파이썬 도구에 의해 추적되지 않습니다.

+0

확장 프로그램이 없지만 다른 사람이 볼 수있는 좋은 곳입니다. –

+0

Django ORM을 사용하는 경우 확장 모듈 -DB-API 데이터베이스 드라이버를 사용합니다. 이 MySQLdb입니까? use_unicode = True (Django> = 1.0의 경우)와 연결되면 현재 버전에서 커서 메모리 누수가 발생합니다. – zgoda

+0

예, 당신이 돈에 옳습니다! 나는 그것들 모두를 사용하고있다. 알려진 모든 솔루션? –

19

settings.py에서 DEBUG = False입니까?

Django가 작성한 모든 SQL 쿼리를 저장하지 않으면 추가됩니다.

+2

와우, 거기에 장고가 도움이 될 것이라는 것을 알았습니다. 예, 제 스크립트는 제 제작 settings.py를 사용하지 않았습니다. *어리둥절한*. 메모리 문제를 해결하는지 확인합니다. –

+0

이것은 그 것이다! DEBUG를 True로 설정하면 대용량 데이터베이스에서 선택할 때 많은 메모리가 소모됩니다. –