Python: debugowanie wycieku pamięci

Mam mały wielowątkowy skrypt uruchomiony w django i z czasem zaczyna zużywać coraz więcej pamięci. Zostawiając go na cały dzień zjada około 6GB PAMIĘCI RAM i zaczynam się wymieniać.

Po http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks widzę to jako najczęstsze typy (z użyciem tylko 800m pamięci):

(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
Co nie pokazuje nic dziwnego. Co powinienem teraz zrobić, aby pomóc debugować pamięć problemy?

Update: próbuje rzeczy, które ludzie polecają. Uruchomiłem program przez noc, a kiedy pracuję, 50% * 8G == 4G pamięci 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

To nie sumuje się do 4G, ani naprawdę nie daje mi żadnych dużych danych strukturalnych, aby go naprawić. Unicode pochodzi z zbioru "wykonanych" węzłów, a lista wygląda jak po prostu losowe weakref s.

Nie używałem guppy, ponieważ wymagało rozszerzenia C i nie miałem roota, więc budowanie było męczące.

Żaden z objectI używało metody have a __del__ i przeglądając biblioteki, nie wygląda to jak django ani python-mysqldb. Jakieś inne pomysły?

Author: Paul Tarjan, 2009-08-27

7 answers

Zobacz http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/. Krótka odpowiedź: jeśli używasz django, ale nie w formacie opartym na żądaniach internetowych, musisz ręcznie uruchomić db.reset_queries() (i oczywiście mieć debug = False, jak inni wspominali). Django automatycznie robi reset_queries() po żądaniu internetowym, ale w Twoim formacie to się nigdy nie zdarza.

 31
Author: Jameson Quinn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-22 07:37:34

Is DEBUG=False in settings.py?

Jeśli nie Django z radością zapisze wszystkie zapytania SQL, które dodajesz.

 21
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-27 18:52:29

Próbowałeś gc?set_debug () ?

Musisz zadać sobie proste pytania:

  • czy używam obiektów z __del__ metodami? Czy absolutnie, jednoznacznie, ich potrzebuję?
  • Czy Mogę uzyskać cykle referencyjne w moim kodzie? Nie możemy złamać tych kół, zanim pozbędziemy się przedmiotów?

Zobacz, głównym problemem będzie cykl obiektów zawierających __del__ metody:

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

Naprawdę zachęcam do oznaczania obiektów / pojęć, które są kolarstwo w aplikacji i skupić się na ich życiu: kiedy nie są już potrzebne, czy mamy coś odniesienia do niego?

Nawet dla cykli bez __del__ metod możemy mieć problem:

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

Jeśli musisz używać słowników podobnych do"widzianych" lub historii, uważaj, aby zachować tylko dane, których potrzebujesz, bez zewnętrznych odniesień do nich.

Jestem teraz trochę rozczarowany set_debug, szkoda, że nie można go skonfigurować do wysyłania danych gdzie indziej niż na stderr, ale miejmy nadzieję, że to się wkrótce zmieni.

 6
Author: Nicolas Dumazet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-27 07:51:26

Zobacz ten doskonały wpis na blogu Neda Batcheldera o tym, jak wyśledzili prawdziwy wyciek pamięci w Tabblo firmy HP. Klasyka i warta przeczytania.

 5
Author: zgoda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-28 10:35:55

Myślę, że powinieneś używać różnych narzędzi. Najwyraźniej statystyki, które masz, dotyczą tylko obiektów GC( tj. obiektów, które mogą uczestniczyć w cyklach); przede wszystkim brakuje w nich ciągów.

Zalecam użycie Pymplera ; powinno to dostarczyć bardziej szczegółowych statystyk.

 1
Author: Martin v. Löwis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-27 07:07:27

Czy używasz jakiegoś rozszerzenia? Są wspaniałym miejscem wycieków pamięci i nie będą śledzone przez narzędzia Pythona.

 1
Author: rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-27 07:34:49

Try Guppy .

Zasadniczo, Potrzebujesz więcej informacji lub być w stanie wyodrębnić niektóre. Guppy zapewnia nawet graficzną reprezentację danych.

 0
Author: iElectric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-27 07:04:24