Python: Memory depuração vazamento

votos
24

Eu tenho um pequeno script de vários segmentos em execução no Django e ao longo do tempo seus começa a usar mais e mais memória. Deixando-o para um dia inteiro come cerca de 6 GB de RAM e eu começo a trocar.

Após http://www.lshift.net/blog/2008/11/14/tracing-python-memory-leaks Eu vejo isso como os tipos mais comuns (com apenas 800M de memória utilizada):

(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

que não mostra nada de estranho. O que devo fazer agora para ajudar a depurar os problemas de memória?

Update: Tentando algumas coisas que as pessoas estão recomendando. Corri o programa durante a noite, e quando eu trabalhar até, 50% * 8G == 4G de memória RAM usado.

(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

Isso não somar 4G, nem realmente me dar quaisquer dados grandes estruturados para ir correção. O unicode é de um set () de nós Concluído e olhar da lista como apenas aleatório weakrefs.

Eu não uso guppy, uma vez que exigia uma extensão C e eu não tinha raiz, por isso ia ser uma dor para construir.

Nenhum dos objecti estava usando ter um __del__método, e olhando através das bibliotecas, que não se parece com Django nem o python-mysqldb fazer qualquer um. Quaisquer outras ideias?

Publicado 27/08/2009 em 07:55
fonte usuário
Em outras línguas...                            


7 respostas

votos
31

Veja http://opensourcehacker.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/ . Resposta curta: se você estiver executando o Django, mas não em um formato baseado em web-request, você precisa executar manualmente db.reset_queries()(e, claro, tem DEBUG = False, como outros já mencionaram). Django faz automaticamente reset_queries()depois de uma solicitação da web, mas em seu formato, que nunca acontece.

Respondeu 10/02/2011 em 14:10
fonte usuário

votos
19

É DEBUG = False no settings.py?

Se não Django irá alegremente armazenar todas as consultas SQL que você faz, que acrescenta-se.

Respondeu 27/08/2009 em 19:52
fonte usuário

votos
6

Já experimentou gc.set_debug () ?

Você precisa perguntar a si mesmo perguntas simples:

  • Estou usando objetos com __del__métodos? Eu absolutamente, inequivocamente, precisa deles?
  • Posso obter ciclos de referência no meu código? não podemos quebrar esses círculos antes de se livrar dos objetos?

Veja, a questão principal seria um ciclo de objetos que contêm __del__métodos:

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

Eu realmente encorajo-vos a bandeira objetos / conceitos que são ciclismo em seu aplicativo e se concentrar em sua vida: quando você não precisa mais deles, nós temos nada referência a ele?

Mesmo para ciclos sem __del__métodos, podemos ter um problema:

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

Se você tem que usar "visto" dicionários -como, ou história, tome cuidado para que você mantenha apenas os dados reais que você precisa, e há referências externas a ele.

Estou um pouco decepcionado agora por set_debug, eu desejo que poderia ser configurado para dados de saída em outro lugar do que para stderr, mas espero que isso deve mudar em breve .

Respondeu 27/08/2009 em 08:26
fonte usuário

votos
5

Veja este excelente post de Ned Batchelder sobre como eles rastreada para baixo vazamento de memória real no Tabblo da HP. Uma leitura clássica e vale a pena.

Respondeu 28/08/2009 em 11:35
fonte usuário

votos
1

Você usar qualquer extensão? Eles são um lugar maravilhoso para vazamentos de memória, e não será monitorado por ferramentas de python.

Respondeu 27/08/2009 em 08:34
fonte usuário

votos
1

Eu acho que você deve usar diferentes ferramentas. Aparentemente, as estatísticas que você tem é apenas cerca de objetos GC (ou seja, objetos que podem participar em ciclos); mais notavelmente, ela não tem cordas.

Eu recomendo usar Pympler ; esta deve lhe fornecer estatísticas mais detalhadas.

Respondeu 27/08/2009 em 08:07
fonte usuário

votos
0

Tente Guppy .

Basicamente, você precisa de mais informações ou ser capaz de extrair alguma. Guppy mesmo proporciona uma representação gráfica de dados.

Respondeu 27/08/2009 em 08:04
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more