Hunting for Memory Leaks in Python applications

Wai Chee Yau

Follow

Feb 13, 2019 – 4 min read

Wir verwenden Python bei Zendesk häufig, um Produkte für maschinelles Lernen (ML) zu entwickeln. Eines der häufigsten Leistungsprobleme, auf die wir bei Anwendungen für maschinelles Lernen gestoßen sind, sind Speicherlecks und -spitzen. Der Python-Code wird normalerweise in Containern über verteilte Verarbeitungsframeworks wie Hadoop, Spark und AWS Batch ausgeführt. Jedem Container wird eine feste Menge an Speicher zugewiesen. Sobald die Codeausführung die festgelegte Speichergrenze überschreitet, wird der Container aufgrund von Fehlern wegen fehlenden Speichers beendet.

Eine schnelle Lösung besteht darin, die Speicherzuweisung zu erhöhen. Dies kann jedoch zu einer Verschwendung von Ressourcen führen und die Stabilität der Produkte aufgrund von unvorhersehbaren Speicherspitzen beeinträchtigen. Die Ursachen für Speicherlecks können sein:

  • Große Objekte, die nicht freigegeben werden
  • Referenzzyklen innerhalb des Codes
  • Unterliegende Bibliotheken/Erweiterungen, die Speicher lecken

Eine nützliche Übung ist die Erstellung eines Profils für die Speichernutzung der Anwendungen, um ein besseres Verständnis für die Speichereffizienz des Codes und der zugrunde liegenden Pakete zu erhalten. Dieser Beitrag behandelt:

  • Profilieren der Speichernutzung der Anwendung über die Zeit
  • Wie man die Speichernutzung in bestimmten Teilen des Programms untersucht
  • Tipps zum Debuggen von Speicherproblemen

Mit dem memory-profile-Paket kann man die Speichernutzung über die Zeit während der Ausführung des Python-Codes betrachten.

# install the required packages
pip install memory_profiler
pip install matplotlib# run the profiler to record the memory usage
# sample 0.1s by defaut
mprof run --include-children python fantastic_model_building_code.py# plot the recorded memory usage
mprof plot --output memory-profile.png

A. Speicherprofil in Abhängigkeit von der Zeit

Die Option include-children bezieht den Speicherverbrauch aller Kindprozesse mit ein, die über den Elternprozess erzeugt werden. Diagramm A zeigt einen iterativen Modelltrainingsprozess, bei dem der Speicher zyklisch ansteigt, wenn Stapel von Trainingsdaten verarbeitet werden. Die Objekte werden freigegeben, sobald die Garbage Collection einsetzt.

Wenn der Speicherverbrauch ständig ansteigt, besteht ein potenzielles Problem mit Speicherlecks. Hier ist ein Beispielskript, um dies zu veranschaulichen.

B. Der Speicherbedarf nimmt mit der Zeit zu

Ein Debugger-Breakpoint kann mit der Option pdb-mmem gesetzt werden, sobald die Speichernutzung einen bestimmten Schwellenwert überschreitet, was bei der Fehlersuche hilfreich ist.

Memory Dump at a Point in Time

Es ist wichtig, die erwartete Anzahl großer Objekte im Programm zu verstehen und ob sie dupliziert und/oder in verschiedene Formate umgewandelt werden sollten.

Um die Objekte im Speicher weiter zu analysieren, kann ein Heap Dump während bestimmter Codezeilen im Programm mit muppy erstellt werden.

Beispiel für die Zusammenfassung eines Speicher-Heap-Dumps

Eine weitere nützliche Memory-Profiling-Bibliothek ist objgraph, die Objektgraphen erzeugen kann, um die Abstammung von Objekten zu untersuchen.

Streben Sie nach einer schnellen Rückkopplungsschleife

Ein nützlicher Ansatz besteht darin, einen kleinen „Testfall“ zu erstellen, der nur den fraglichen Code mit dem Speicherleck ausführt. Ziehen Sie in Erwägung, eine Teilmenge der zufällig abgetasteten Daten zu verwenden, wenn die Ausführung der gesamten Eingabedaten langwierig ist.

Speicherintensive Aufgaben in einem separaten Prozess ausführen

Python gibt den Speicher nicht unbedingt sofort an das Betriebssystem zurück. Um sicherzustellen, dass der Speicher nach der Ausführung eines Codes freigegeben wird, muss dieser in einem separaten Prozess ausgeführt werden. Diese Seite enthält weitere Details zur Python-Garbage-Collection.

Debugger kann Verweise auf Objekte hinzufügen

Wenn ein Breakpoint-Debugger wie pdb verwendet wird, bleiben alle Objekte, die manuell vom Debugger erstellt und referenziert werden, im Speicherprofil. Dies kann einen falschen Eindruck von Speicherlecks erwecken, wenn Objekte nicht rechtzeitig freigegeben werden.

Aufpassen auf Pakete, die undicht sein können

Einige Python-Bibliotheken können möglicherweise Speicherlecks haben. Z.B. hat pandas einige bekannte Probleme mit Speicherlecks.

Happy hunting!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.