Tengo un script de larga ejecución que, si se deja correr el tiempo suficiente, consumirá toda la memoria de mi sistema.
Sin entrar en detalles sobre el guión, tengo dos preguntas:
- ¿Hay alguna "mejor práctica" a seguir, que ayudará a evitar que se produzcan fugas?
- ¿Qué técnicas existen para depurar las pérdidas de memoria en Python?
python
debugging
memory-management
memory-leaks
Fragsworth
fuente
fuente
__del__
método que ya no se hace referencia a excepción de su ciclo. El ciclo no se puede romper debido a problemas con__del__
. ¡Arreglalo!Respuestas:
Eche un vistazo a este artículo: Rastreo de pérdidas de memoria en Python
Además, tenga en cuenta que el módulo de recolección de basura en realidad puede tener marcas de depuración establecidas. Mira la
set_debug
función. Además, mire este código de Gnibbler para determinar los tipos de objetos que se han creado después de una llamada.fuente
Probé la mayoría de las opciones mencionadas anteriormente, pero encontré que este paquete pequeño e intuitivo es el mejor: pympler
Es bastante sencillo rastrear objetos que no se recolectaron como basura, consulte este pequeño ejemplo:
instalar paquete a través de
pip install pympler
La salida muestra todos los objetos que se han agregado, más la memoria que consumieron.
Salida de muestra:
Este paquete proporciona una serie de características más. Consulte la documentación de pympler , en particular la sección Identificación de pérdidas de memoria .
fuente
pympler
puede ser LENTO . Si está haciendo algo semi-en tiempo real, puede afectar por completo el rendimiento de su aplicación.Déjame recomendarte la herramienta mem_top que creé
Me ayudó a resolver un problema similar.
Muestra instantáneamente los principales sospechosos de pérdidas de memoria en un programa Python
fuente
El módulo Tracemalloc se integró como un módulo incorporado a partir de Python 3.4, y aparentemente, también está disponible para versiones anteriores de Python como una biblioteca de terceros (aunque no lo he probado).
Este módulo puede generar los archivos y líneas precisos que asignaron la mayor cantidad de memoria. En mi humilde opinión, esta información es infinitamente más valiosa que la cantidad de instancias asignadas para cada tipo (que termina siendo muchas tuplas el 99% del tiempo, lo cual es una pista, pero apenas ayuda en la mayoría de los casos).
Le recomiendo que use tracemalloc en combinación con piratasita . 9 de cada 10 veces, ejecutar el fragmento de código de los 10 mejores en un caparazón de piratasita le dará suficiente información y sugerencias para corregir la fuga en 10 minutos. Sin embargo, si aún no puede encontrar la causa de la fuga, la cáscara de pyrasite en combinación con las otras herramientas mencionadas en este hilo probablemente también le dará más pistas. También debe echar un vistazo a todos los ayudantes adicionales proporcionados por pyrasite (como el visor de memoria).
fuente
Deberías echar un vistazo especialmente a tus datos globales o estáticos (datos de larga duración).
Cuando estos datos crecen sin restricciones, también puede tener problemas en Python.
El recolector de basura solo puede recopilar datos, a los que ya no se hace referencia. Pero sus datos estáticos pueden conectar elementos de datos que deberían liberarse.
Otro problema pueden ser los ciclos de memoria, pero al menos en teoría el recolector de basura debería encontrar y eliminar ciclos, al menos siempre que no estén enganchados con algunos datos de larga duración.
¿Qué tipos de datos de larga duración son especialmente problemáticos? Eche un buen vistazo a las listas y diccionarios: pueden crecer sin límite. En los diccionarios puede que incluso no veas los problemas que vienen, ya que cuando accedes a los dictados, la cantidad de claves en el diccionario puede no ser de gran visibilidad para ti ...
fuente
Para detectar y localizar pérdidas de memoria para procesos de larga ejecución, por ejemplo, en entornos de producción, ahora puede usar stackimpact . Utiliza tracemalloc debajo. Más información en este post .
fuente
En cuanto a las mejores prácticas, esté atento a las funciones recursivas. En mi caso, me encontré con problemas de recursión (donde no era necesario que hubiera). Un ejemplo simplificado de lo que estaba haciendo:
operar de esta manera recursiva no desencadenará la recolección de basura y eliminará los restos de la función, por lo que cada vez que el uso de la memoria crece y crece.
Mi solución fue extraer la llamada recursiva de my_function () y tener el controlador main () cuando llamarla nuevamente. De esta manera, la función termina de forma natural y se limpia después de sí misma.
fuente
No estoy seguro acerca de las "Mejores prácticas" para las pérdidas de memoria en Python, pero Python debería borrar su propia memoria mediante su recolector de basura. Así que principalmente comenzaría por buscar una lista circular de algunos cortos, ya que el recolector de basura no los recogerá.
fuente
Este no es un consejo exhaustivo. Pero una cosa importante a tener en cuenta al escribir con la idea de evitar futuras pérdidas de memoria (bucles) es asegurarse de que cualquier cosa que acepte una referencia a una devolución de llamada, debe almacenar esa devolución de llamada como una referencia débil.
fuente