Python-Speicherlecks [geschlossen]


180

Ich habe ein Skript mit langer Laufzeit, das, wenn es lange genug ausgeführt wird, den gesamten Speicher auf meinem System belegt.

Ohne auf Details zum Skript einzugehen, habe ich zwei Fragen:

  1. Gibt es "Best Practices", die dazu beitragen, das Auftreten von Lecks zu verhindern?
  2. Welche Techniken gibt es, um Speicherlecks in Python zu debuggen?

5
Ich fand dieses Rezept hilfreich.
David Schein

Es scheint viel zu viele Daten auszudrucken, um nützlich zu sein
Casebash

1
@Casebash: Wenn diese Funktion etwas druckt, machen Sie es ernsthaft falsch. Es werden Objekte mit __del__Methoden aufgelistet , auf die bis auf ihren Zyklus nicht mehr verwiesen wird. Der Zyklus kann aufgrund von Problemen mit nicht unterbrochen werden __del__. Repariere es!
Helmut Grohne

Antworten:



83

Ich habe die meisten zuvor genannten Optionen ausprobiert, fand dieses kleine und intuitive Paket jedoch das beste: Pympler

Es ist ganz einfach, Objekte zu verfolgen, die nicht durch Müll gesammelt wurden. Überprüfen Sie dieses kleine Beispiel:

Paket installieren über pip install pympler

from pympler.tracker import SummaryTracker
tracker = SummaryTracker()

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

tracker.print_diff()

Die Ausgabe zeigt Ihnen alle hinzugefügten Objekte sowie den von ihnen verbrauchten Speicher.

Beispielausgabe:

                                 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

Dieses Paket bietet eine Reihe weiterer Funktionen. Überprüfen Sie die Dokumentation des Pymplers , insbesondere den Abschnitt Identifizieren von Speicherlecks .


5
Es ist erwähnenswert, dass pymplerdies langsam sein kann . Wenn Sie etwas in Echtzeit ausführen, kann dies Ihre Anwendungsleistung vollständig beeinträchtigen.
Gefälschter Name

@sebpiq seltsamerweise passiert mir das gleiche ... hast du eine Ahnung, warum das passiert? Ein kurzer Blick auf den Quellcode gab keine wirklichen Einblicke.
Linusg

25

Lassen Sie mich das von mir erstellte mem_top- Tool empfehlen

Es hat mir geholfen, ein ähnliches Problem zu lösen

Es zeigt sofort die Hauptverdächtigen für Speicherlecks in einem Python-Programm


1
das ist wahr ... aber es gibt sehr wenig in der Art der Verwendung / Erklärung der Ergebnisse
me_

@me_, in diesem Tool sind die Abschnitte "Verwendung" und "Ergebnis erklären" dokumentiert. Sollte ich eine Erklärung hinzufügen wie "refs ist die Anzahl der Referenzen aus dem Objekt, types ist die Anzahl der Objekte dieses Typs, bytes ist die Größe des Objekts" - wäre es nicht zu offensichtlich, dies zu dokumentieren?
Denis Ryzhkov

Die Verwendungsdokumente des Tools enthalten eine einzige Zeile mit der Aufschrift "von Zeit zu Zeit: logging.debug (mem_top ())", während die Erklärung der Ergebnisse die reale Erfahrung des Autors bei der Fehlerverfolgung ohne Kontext ist. Dies ist keine technische Spezifikation, die dies aussagt ein Entwickler genau das, was sie sehen ... Ich klopfe nicht an Ihre Antwort ... es zeigt hochrangige Verdächtige als in Rechnung gestellt ... es gibt keine ausreichende Dokumentation, um das Ergebnis der Verwendung vollständig zu verstehen ... zum Beispiel Warum ist der "GearmanJobRequest" in der Ausgabe "Explaining Results" offensichtlich ein Problem? Keine Erklärung, warum ...
me_

1
Ich glaube, ich
klopfe

6
@me_, ich habe gerade den nächsten Schritt zu "Verwendung" hinzugefügt, den Abschnitt "Zähler" hinzugefügt, eine Erklärung hinzugefügt, warum genau Gearman in diesem Beispiel aus dem wirklichen Leben ein Verdächtiger war, und jeden optionalen Parameter von "mem_top ()" im Code dokumentiert. und dies alles als v0.1.7 hochgeladen - bitte schauen Sie nach, ob noch etwas verbessert werden könnte. Danke dir! )
Denis Ryzhkov

18

Das Tracemalloc-Modul wurde ab Python 3.4 als integriertes Modul integriert und ist anscheinend auch für frühere Versionen von Python als Bibliothek eines Drittanbieters verfügbar (hat es jedoch nicht getestet).

Dieses Modul kann die genauen Dateien und Zeilen ausgeben, die den meisten Speicher zugewiesen haben. IMHO, diese Informationen sind unendlich wertvoller als die Anzahl der zugewiesenen Instanzen für jeden Typ (was in 99% der Fälle eine Menge Tupel darstellt, was ein Hinweis ist, aber in den meisten Fällen kaum hilft).

Ich empfehle Ihnen, Tracemalloc in Kombination mit Pyrasit zu verwenden . Wenn Sie das Top-10-Snippet 9 Mal von 10 Mal in einer Pyrasit-Schale ausführen , erhalten Sie genügend Informationen und Hinweise, um das Leck innerhalb von 10 Minuten zu beheben. Wenn Sie die Leckursache immer noch nicht finden können, gibt Ihnen die Pyrasit-Schale in Kombination mit den anderen in diesem Thread genannten Werkzeugen wahrscheinlich auch weitere Hinweise. Sie sollten sich auch alle zusätzlichen Helfer von Pyrasite ansehen (z. B. den Memory Viewer).


12

Sie sollten sich insbesondere Ihre globalen oder statischen Daten (langlebige Daten) ansehen.

Wenn diese Daten ohne Einschränkung wachsen, können auch in Python Probleme auftreten.

Der Garbage Collector kann nur Daten erfassen, auf die nicht mehr verwiesen wird. Ihre statischen Daten können jedoch Datenelemente verbinden, die freigegeben werden sollen.

Ein weiteres Problem können Speicherzyklen sein, aber zumindest theoretisch sollte der Garbage Collector Zyklen finden und eliminieren - zumindest solange sie nicht an langlebige Daten gebunden sind.

Welche Arten von langlebigen Daten sind besonders problematisch? Sehen Sie sich Listen und Wörterbücher genau an - sie können unbegrenzt wachsen. In Wörterbüchern sehen Sie möglicherweise sogar keine Probleme, da beim Zugriff auf Wörterbücher die Anzahl der Schlüssel im Wörterbuch für Sie möglicherweise nicht besonders gut sichtbar ist ...



4

Achten Sie bei Best Practices auf rekursive Funktionen. In meinem Fall stieß ich auf Probleme mit der Rekursion (wo es keine geben musste). Ein vereinfachtes Beispiel dafür, was ich tat:

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

Wenn Sie auf diese rekursive Weise arbeiten, wird die Speicherbereinigung nicht ausgelöst und die Reste der Funktion werden nicht entfernt, sodass die Speichernutzung jedes Mal zunimmt.

Meine Lösung bestand darin, den rekursiven Aufruf aus my_function () zu ziehen und main () zu behandeln, wann er erneut aufgerufen werden soll. Auf diese Weise endet die Funktion auf natürliche Weise und räumt nach sich selbst auf.

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

6
Die Verwendung der Rekursion auf diese Weise wird auch unterbrochen, wenn Sie die Rekursionstiefengrenze erreichen, da Python die Tail-Aufrufe nicht optimiert. Standardmäßig sind dies 1000 rekursive Aufrufe.
Lie Ryan

3

Sie sind sich nicht sicher über "Best Practices" für Speicherlecks in Python, aber Python sollte seinen eigenen Speicher durch seinen Garbage Collector löschen. Also würde ich hauptsächlich nach einer kreisförmigen Liste von Kurzfilmen suchen, da diese nicht vom Müllsammler abgeholt werden.


3
oder Verweise auf Objekte, die für immer aufbewahrt werden, etc
matt b

3
Könnt ihr bitte Beispiele für kreisförmige Listen und Objekte liefern, die für immer aufbewahrt werden?
Daniel

2

Dies ist kein erschöpfender Rat. Das Wichtigste beim Schreiben mit dem Gedanken, zukünftige Speicherlecks (Schleifen) zu vermeiden, ist jedoch sicherzustellen, dass alles, was einen Verweis auf einen Rückruf akzeptiert, diesen Rückruf als schwache Referenz speichert.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.