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?
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.
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.
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.
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.
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.
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.
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.
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