2016-05-04 37 views
4

Ich benutze die C-API eines Anbieters für eine Business-Software, indem ich ihre Bibliothek mit dem Ctypes-Modul von Python lade.Wie umgehen Sie ein Speicherleck in einer Hersteller-DLL, die in Python verwendet wird?

Nach der Bereitstellung der Software, die ich schrieb, fand ich, dass die Bibliothek des Anbieters Speicher auf einer konsistenten und vorhersehbaren Basis verliert, entsprechend der Anzahl der Aufrufe einer bestimmten Funktion, die Teil ihrer API ist.

ich dupliziert sogar das Leck in einem C-Programm, das keine Heapzuweisungen verwendet.

kontaktierte ich mit dem Verkäufer über das Thema, und sie sagten, dass sie daran arbeiten, aber ich kann wahrscheinlich ein Update bis zur nächsten Version der Software nicht realistisch erwarten.

hatte ich die Idee des Verkäufer dll nach einer bestimmten Schwelle der Anrufe an die undichten Funktion Nachladen, aber den ausgetretenen Speicher nicht freigeben.

fand ich, dass ich die Bibliothek wie so zu entladen zwingen könnte:

_ctypes.FreeLibrary(vendor_dll._handle) 

Dies gibt den Speicher, sondern bewirkt, dass den Dolmetscher scheinbar zufällig nach einer bestimmten Anzahl von Minuten sind die Verwendung des Herstellers zum Absturz API.

ich dieses Problem in den Python-Bug-Tracker gefunden, die meine Situation beschreibt: https://bugs.python.org/issue14597

Es scheint, dass, wenn es noch ein offener Verweis auf die Bibliothek, sie zwingen wird unweigerlich zu entladen das Python-Interpreter zum Absturz bringen.

Im schlimmsten Fall denke ich, ich könnte die Bibliothek des Anbieters in einem separaten Prozess laden, Proxy-Anfragen mit einer Multiprocessing Queue und einen Watchdog einrichten, um den Prozess neu zu erstellen, wenn der Interpreter stirbt.

Gibt es einen besseren Weg, dies zu umgehen?

+0

Ich nehme eine elegantere Lösung für meine obige Abhilfe wäre, um den Arbeitsprozess zu einem regelmäßigen Intervall zu beenden und neu starten. Dies würde es ermöglichen, dass der durch die Bibliothek des Herstellers ausgelöste Speicher frei wird, aber den Interpreter nicht zum Absturz bringen würde. – jakogut

+0

Wenn das Freigeben der Bibliothek funktioniert, ist es nicht wirklich ein Speicherleck. Die Bibliothek muss diese Zuordnungen verfolgen, um sie auf "DLL_PROCESS_DETACH" freizugeben. Beim Entladen von 'vendor_dll' sollten Sie zuerst alle Verweise auf die aktuelle Instanz entfernen und sicherstellen, dass nichts seinen Code erneut ausführt, einschließlich ausstehender asynchroner Rückrufe. Dann können Sie die DLL entladen und neu laden. Gemeinsame Bibliotheken werden als Referenz gezählt. Um sicherzustellen, dass sie tatsächlich entladen sind, rufen Sie 'FreeLibrary' auf, bis ein' OSError' ausgelöst wird. – eryksun

Antwort

1

Am Ende befestigte ich das Problem, indem die Hersteller-Bibliothek in einem separaten Prozess geladen, und es durch Pyro4 Zugriff, etwa so:

class LibraryWorker(multiprocessing.Process): 
    def __init__(self): 
     super().__init__() 

    def run(self): 
     self.library = ctypes.windll.LoadLibrary(
      'vendor_library.dll') 

     Pyro4.serveSimple(
      {self, 'library'}, 
      ns=False) 

    def lib_func(self): 
     res = self.library.func() 
     return res 

Es ist ein bisschen mehr Arbeit war es, den alten Code zu massieren ctypes Zeiger zwischen den beiden Prozessen nicht übergeben, aber es funktioniert.

Mit der Bibliothek in einem separaten Prozess geladen wird, kann ich den Überblick über die Speicherauslastung halten. Wenn es zu hoch wird, kann ich den Prozess beenden und neu erstellen, um den Speicher freizugeben.

Verwandte Themen