Escribí un programa Python que actúa en un archivo de entrada grande para crear algunos millones de objetos que representan triángulos. El algoritmo es:
- leer un archivo de entrada
- procesar el archivo y crear una lista de triángulos, representados por sus vértices
- genera los vértices en el formato OFF: una lista de vértices seguida de una lista de triángulos. Los triángulos están representados por índices en la lista de vértices.
El requisito de OFF de que imprima la lista completa de vértices antes de imprimir los triángulos significa que tengo que mantener la lista de triángulos en la memoria antes de escribir la salida en el archivo. Mientras tanto, recibo errores de memoria debido al tamaño de las listas.
¿Cuál es la mejor manera de decirle a Python que ya no necesito algunos de los datos y que se pueden liberar?
python
memory
memory-management
Nathan Fellman
fuente
fuente
Respuestas:
De acuerdo con la documentación oficial de Python , puede forzar al recolector de basura a liberar memoria sin referencia
gc.collect()
. Ejemplo:fuente
gc.collect()
sí mismo al final de un ciclo puede ayudar a evitar la fragmentación de la memoria, lo que a su vez ayuda a mantener el rendimiento. He visto que esto hace una diferencia significativa (~ 20% de tiempo de ejecución IIRC)gc.collect()
después de cargar un marco de datos de pandas desde hdf5 (500k filas) redujo el uso de memoria de 1.7GB a 500MBdel my_array
seguido degc.collect()
después de procesar la matriz es la única forma en que se libera la memoria y mi proceso sobrevive para cargar la siguiente matriz.Desafortunadamente (dependiendo de su versión y versión de Python), algunos tipos de objetos usan "listas libres" que son una optimización local ordenada pero que pueden causar fragmentación de la memoria, específicamente al hacer que cada vez más memoria "asignada" solo para objetos de cierto tipo y por lo tanto no está disponible para el "fondo general".
La única forma realmente confiable de garantizar que un uso grande pero temporal de la memoria DEBE devolver todos los recursos al sistema cuando se hace, es hacer que ese uso ocurra en un subproceso, lo que hace que el trabajo que consume mucha memoria finalice. En tales condiciones, el sistema operativo REALIZARÁ su trabajo y con mucho gusto reciclará todos los recursos que el subproceso puede haber consumido. Afortunadamente, el
multiprocessing
módulo hace que este tipo de operación (que solía ser bastante difícil) no sea tan malo en las versiones modernas de Python.En su caso de uso, parece que la mejor manera para que los subprocesos acumulen algunos resultados y, sin embargo, se aseguren de que esos resultados estén disponibles para el proceso principal es usar archivos semi-temporales (quiero decir, semi-temporal, NO el tipo de archivos que desaparecerá automáticamente cuando se cierre, solo archivos normales que elimine explícitamente cuando haya terminado con ellos).
fuente
multiprocessing.Manager
lugar de archivos para implementar el estado compartido.La
del
declaración podría ser útil, pero IIRC no garantiza que libere la memoria . Los documentos están aquí ... y el por qué no se publica aquí .He escuchado a personas en sistemas tipo Linux y Unix bifurcar un proceso de Python para hacer un trabajo, obtener resultados y luego matarlo.
Este artículo tiene notas sobre el recolector de basura Python, pero creo que la falta de control de memoria es la desventaja de la memoria administrada
fuente
Python se recolecta basura, por lo que si reduce el tamaño de su lista, recuperará memoria. También puede usar la declaración "del" para deshacerse completamente de una variable:
fuente
No puedes liberar memoria explícitamente. Lo que debe hacer es asegurarse de no mantener referencias a objetos. Luego se recolectará basura, liberando la memoria.
En su caso, cuando necesita listas grandes, normalmente necesita reorganizar el código, generalmente utilizando generadores / iteradores en su lugar. De esa manera, no necesita tener las listas grandes en la memoria.
http://www.prasannatech.net/2009/07/introduction-python-generators.html
fuente
(
del
puede ser su amigo, ya que marca los objetos como borrables cuando no hay otras referencias a ellos. Ahora, a menudo el intérprete de CPython guarda esta memoria para su uso posterior, por lo que su sistema operativo podría no ver la memoria "liberada").Quizás, en primer lugar, no se encuentre con ningún problema de memoria utilizando una estructura más compacta para sus datos. Por lo tanto, las listas de números son mucho menos eficientes en memoria que el formato utilizado por el
array
módulo estándar o elnumpy
módulo de terceros . Ahorraría memoria colocando sus vértices en una matriz NumPy 3xN y sus triángulos en una matriz de N elementos.fuente
del
no hace nada que simplemente reasignar un valor diferente a todos los nombres que hacen referencia a un objeto no lo haría.del
libera la memoria desde el punto de vista de Python, pero generalmente no desde el punto de vista de la biblioteca de tiempo de ejecución C o del sistema operativo. Referencias: stackoverflow.com/a/32167625/4297 , effbot.org/pyfaq/… .del
es igualmente eficaz con salidas-de-alcance, los cambios de destino, etc.Tuve un problema similar al leer un gráfico de un archivo. El procesamiento incluyó el cálculo de una matriz flotante de 200 000x200 000 (una línea a la vez) que no cabía en la memoria. Tratar de liberar la memoria entre los cálculos utilizando
gc.collect()
el aspecto fijo del problema relacionado con la memoria, pero resultó en problemas de rendimiento: no sé por qué, pero a pesar de que la cantidad de memoria utilizada permaneció constante, cada nueva llamadagc.collect()
tomó más tiempo que El anterior. Así que bastante rápido la recolección de basura tomó la mayor parte del tiempo de cálculo.Para solucionar los problemas de memoria y rendimiento, cambié al uso de un truco de subprocesos múltiples que leí una vez en algún lugar (lo siento, ya no puedo encontrar la publicación relacionada). Antes de leer cada línea del archivo en un gran
for
bucle, procesarlo y ejecutarlo degc.collect()
vez en cuando para liberar espacio en la memoria. Ahora llamo a una función que lee y procesa un fragmento del archivo en un nuevo hilo. Una vez que finaliza el subproceso, la memoria se libera automáticamente sin el extraño problema de rendimiento.Prácticamente funciona así:
fuente
Otros han publicado algunas formas en que podría "convencer" al intérprete de Python para que libere la memoria (o evite tener problemas de memoria). Lo más probable es que primero pruebes sus ideas. Sin embargo, creo que es importante darle una respuesta directa a su pregunta.
Realmente no hay ninguna forma de decirle directamente a Python que libere memoria. El hecho es que si desea un nivel de control tan bajo, tendrá que escribir una extensión en C o C ++.
Dicho esto, hay algunas herramientas para ayudar con esto:
fuente
Si no le importa la reutilización de vértices, podría tener dos archivos de salida: uno para vértices y otro para triángulos. Luego agregue el archivo de triángulo al archivo de vértice cuando haya terminado.
fuente