Eu escrevi um programa Python que atua em um grande arquivo de entrada para criar alguns milhões de objetos representando triângulos. O algoritmo é:
- ler um arquivo de entrada
- processe o arquivo e crie uma lista de triângulos, representada por seus vértices
- produz os vértices no formato OFF: uma lista de vértices seguida por uma lista de triângulos. Os triângulos são representados por índices na lista de vértices
O requisito de OFF que eu imprima a lista completa de vértices antes de imprimir os triângulos significa que tenho que manter a lista de triângulos na memória antes de gravar a saída no arquivo. Enquanto isso, estou recebendo erros de memória por causa dos tamanhos das listas.
Qual é a melhor maneira de dizer ao Python que não preciso mais de alguns dados e que eles podem ser liberados?
python
memory
memory-management
Nathan Fellman
fonte
fonte
Respostas:
De acordo com a documentação oficial do Python , você pode forçar o Garbage Collector a liberar memória não referenciada
gc.collect()
. Exemplo:fonte
gc.collect()
si mesmo no final de um loop pode ajudar a evitar a fragmentação da memória, o que, por sua vez, ajuda a manter o desempenho. Eu já vi isso faz uma diferença significativa (~ 20% de tempo de execução IIRC)gc.collect()
depois de carregar uma trama de dados de pandas de HDF5 (500k linhas) reduziu o uso de memória de 1.7 GB para 500 MBdel my_array
seguido degc.collect()
depois do processamento da matriz é a única maneira pela qual a memória é realmente liberada e meu processo sobrevive para carregar a próxima matriz.Infelizmente (dependendo da sua versão e lançamento do Python), alguns tipos de objetos usam "listas gratuitas", que são uma otimização local pura, mas podem causar fragmentação da memória, especificamente tornando cada vez mais a memória "reservada" apenas para objetos de um determinado tipo e portanto indisponível para o "fundo geral".
A única maneira realmente confiável de garantir que um uso amplo, mas temporário de memória, devolva todos os recursos ao sistema quando terminar, é fazer com que esse uso ocorra em um subprocesso, que finaliza o trabalho que requer muita memória. Sob tais condições, o sistema operacional fará seu trabalho e alegremente reciclará todos os recursos que o subprocesso pode ter consumido. Felizmente, o
multiprocessing
módulo torna esse tipo de operação (que costumava ser uma dor) não muito ruim nas versões modernas do Python.No seu caso de uso, parece que a melhor maneira de os subprocessos acumularem alguns resultados e ainda garantir que esses resultados estejam disponíveis para o processo principal é usar arquivos semi-temporários (por semi-temporário, quero dizer, NÃO o tipo de arquivo que desaparecem automaticamente quando fechadas, apenas os arquivos comuns que você exclui explicitamente quando termina o processo).
fonte
multiprocessing.Manager
vez de arquivos, para implementar o estado compartilhado.A
del
declaração pode ser útil, mas o IIRC não garante a liberação da memória . Os documentos estão aqui ... e um motivo pelo qual não foi divulgado está aqui .Eu ouvi pessoas nos sistemas Linux e Unix do tipo bifurcando um processo python para fazer algum trabalho, obter resultados e depois matá-lo.
Este artigo possui notas sobre o coletor de lixo Python, mas acho que a falta de controle de memória é a desvantagem da memória gerenciada
fonte
O Python é coletado pelo lixo, portanto, se você reduzir o tamanho da sua lista, ele recuperará a memória. Você também pode usar a instrução "del" para se livrar completamente de uma variável:
fonte
Você não pode liberar explicitamente a memória. O que você precisa fazer é garantir que não mantenha referências a objetos. Eles serão coletados como lixo, liberando a memória.
No seu caso, quando você precisa de listas grandes, normalmente precisa reorganizar o código, geralmente usando geradores / iteradores. Dessa forma, você não precisa ter as grandes listas na memória.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
fonte
(
del
pode ser seu amigo, pois marca os objetos como deletáveis quando não há outras referências a eles. Agora, geralmente o intérprete do CPython mantém essa memória para uso posterior, para que seu sistema operacional não veja a memória "liberada".)Talvez você não tenha problemas de memória em primeiro lugar usando uma estrutura mais compacta para seus dados. Assim, as listas de números são muito menos eficientes em termos de memória do que o formato usado pelo
array
módulo padrão ou pelonumpy
módulo de terceiros . Você economizaria memória colocando seus vértices em uma matriz NumPy 3xN e seus triângulos em uma matriz de elementos N.fonte
del
não faz nada que apenas reatribuir um valor diferente a todos os nomes que referenciam um objeto.del
libera a memória do ponto de vista do Python, mas geralmente não do ponto de vista da biblioteca de tempo de execução C ou do SO. Referências: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/… .del
é igualmente eficaz com saídas fora do escopo, reatribuições etc.Eu tive um problema semelhante ao ler um gráfico de um arquivo. O processamento incluiu o cálculo de uma matriz flutuante de 200 000 x 200 000 (uma linha de cada vez) que não cabia na memória. Tentando liberar a memória entre os cálculos usando
gc.collect()
o aspecto relacionado à memória do problema, mas resultou em problemas de desempenho: não sei por que, embora a quantidade de memória usada permanecesse constante, cada nova chamadagc.collect()
levava mais tempo do que o anterior. Tão rapidamente que a coleta de lixo levou a maior parte do tempo computacional.Para corrigir os problemas de memória e desempenho, mudei para o uso de um truque de multithreading que li uma vez em algum lugar (desculpe, não consigo mais encontrar a postagem relacionada). Antes eu estava lendo cada linha do arquivo em um
for
loop grande , processando-o e executando degc.collect()
vez em quando para liberar espaço de memória. Agora, chamo uma função que lê e processa um pedaço do arquivo em um novo thread. Quando o segmento termina, a memória é automaticamente liberada sem o problema de desempenho estranho.Praticamente funciona assim:
fonte
Outros publicaram algumas maneiras pelas quais você pode "convencer" o interpretador Python a liberar a memória (ou evitar outros problemas de memória). Provavelmente, você deve experimentar suas idéias primeiro. No entanto, acho importante dar uma resposta direta à sua pergunta.
Não há realmente nenhuma maneira de dizer diretamente ao Python para liberar memória. O fato é que, se você deseja um nível de controle tão baixo, precisará escrever uma extensão em C ou C ++.
Dito isto, existem algumas ferramentas para ajudar com isso:
fonte
Se você não se importa com a reutilização de vértices, pode ter dois arquivos de saída - um para vértices e outro para triângulos. Acrescente o arquivo triângulo ao arquivo de vértice quando terminar.
fonte