Fugas de memória em Python

Tenho um guião de longa duração que, se for suficiente, consumirá toda a memória do meu sistema.

Sem entrar em detalhes sobre o guião, tenho duas perguntas:
    Há alguma "melhor prática" a seguir, que ajude a evitar fugas? Que técnicas existem para depurar fugas de memória em Python?
Author: Fragsworth, 2009-09-17

9 answers

Veja este artigo: rastreando fugas de memória em python

Além disso, note que o módulo de recolha do lixo pode realmente ter as opções de depuração definidas. Olha para a função set_debug. Além disso, veja este código por Gnibbler para determinar os tipos de objetos que foram criados após uma chamada.

 77
Author: ChristopheD, 2017-10-08 01:41:11

Eu tentei a maioria das opções mencionadas anteriormente, mas achei este pequeno e intuitivo pacote para ser o melhor: pympler

É muito direto para a frente para rastrear objetos que não foram coletados lixo, confira este pequeno exemplo:

Instalar o pacote via pip install pympler

from pympler.tracker import SummaryTracker
tracker = SummaryTracker()

# ... some code you want to investigate ...

tracker.print_diff()

A saída mostra todos os objectos que foram adicionados, mais a memória que consumiram.

Saída da amostra:

                                 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

Este pacote fornece uma série de outras funcionalidades. Verificar a documentação do pympler, em particular a secção que identifica fugas de memória.

 61
Author: linqu, 2016-05-20 07:38:37

Deixe-me recomendar mem_top tool,
isso ajudou-me a resolver um problema semelhante.

Mostra instantaneamente os principais suspeitos de fugas de memória num programa Python.
 19
Author: Denis Ryzhkov, 2014-05-27 07:32:36

Você deve especialmente dar uma olhada em seus dados globais ou estáticos (dados de vida longa).

Quando estes dados crescem sem restrições, Você também pode ter problemas em Python.

O coletor de lixo só pode coletar dados, que já não são referenciados. Mas os seus dados estáticos podem juntar elementos de dados que devem ser libertados. Outro problema pode ser os ciclos de memória, mas, pelo menos em teoria, o coletor de lixo deve encontrar e eliminar os ciclos-pelo menos enquanto eles não estão viciados em dados de vida longa. Que tipo de dados de vida longa são especialmente problemáticos? Dê uma boa olhada em todas as listas e dicionários -- eles podem crescer sem qualquer limite. Nos dicionários você pode até mesmo não ver o problema que vem desde quando você acessar dicts, o número de chaves no dicionário pode não ser de grande visibilidade para você ...
 9
Author: Juergen, 2014-04-08 06:03:33

O módulo Tracemalloc foi integrado como um módulo integrado a partir do Python 3.4, e, normalmente, também está disponível para versões anteriores do Python como uma biblioteca de terceiros (ainda não o testei).

Este módulo é capaz de enviar os arquivos e linhas precisos que alocaram mais memória. IMHO, esta informação é infinitamente mais valiosa do que o número de instâncias alocadas para cada tipo (que acaba sendo um monte de tuplas 99% do tempo, que é uma pista, mas pouco ajuda na maioria dos casos).

Recomendo que utilize tracemalloc em combinação com pirasite . 9 vezes em cada 10, executar o Top 10 snippet numa concha de pirasite dar-lhe-á informações e dicas suficientes para corrigir a fuga em 10 minutos. No entanto, se você ainda é incapaz de encontrar a causa de vazamento, pyrasite-shell em combinação com as outras ferramentas mencionadas neste tópico provavelmente lhe dará algumas dicas também. Você também deve dar uma olhada em todos os ajudantes extras fornecidos pela pirasita (como o visualizador de memória).

 6
Author: user1527491, 2017-08-16 19:40:05

Não tenho a certeza sobre as "melhores práticas" para fugas de memória em python, mas python deve limpar a sua própria memória pelo seu coletor de lixo. Então, principalmente, eu começaria por verificar a lista circular de algum curto, uma vez que eles não serão pegos pelo coletor de lixo.

 4
Author: martiert, 2009-09-16 20:59:56

Para detectar e localizar fugas de memória para processos de longa duração, por exemplo em ambientes de produção, pode agora utilizar stackimpact. Ele usa tracemalloc por baixo. Mais informações em este post .

enter image description here

 4
Author: logix, 2017-07-01 08:05:51
Isto não é de modo algum um conselho exaustivo. Mas a primeira coisa a ter em mente ao escrever com o pensamento de evitar futuros vazamentos de memória (loops) é certificar-se de que qualquer coisa que aceita uma referência a um call-back, deve armazenar esse call-back como uma referência fraca.
 3
Author: Dmitry Rubanovich, 2012-02-19 20:32:21

Quanto às melhores práticas, fique atento às funções recursivas. No meu caso, eu encontrei problemas com a recursão (onde não precisava ser). Um exemplo simplificado do que eu estava fazendo:

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

Operar desta forma recursiva não irá despoletar a recolha de lixo e limpar os restos da função, por isso, cada vez através do uso da memória está a crescer e a crescer.

A minha solução era retirar a chamada recursiva da minha função () e ter a pega principal() quando ligar outra vez. desta forma, a função termina naturalmente e limpa depois de si mesma.

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()
 2
Author: The4thIceman, 2017-03-03 21:55:14