Umgang mit einer nicht verwalteten DLL mit einem Speicherleck

8

Ich habe eine c # -Anwendung, die von einer unmanaged Assembly eines Drittanbieters abhängt, um auf bestimmte Hardware zuzugreifen.

Der nicht verwaltete Code weist einen Speicherverlust auf, der den Speicherverbrauch nach jedem Zugriff um ca. 10 MB erhöht. Das Problem ist bekannt; Es ist kein Bugfix verfügbar.

Gibt es eine Möglichkeit, diese Assembly weiterhin ohne regelmäßige Neustarts zu verwenden?

Ich habe versucht, eine separate AppDomain zu erstellen, den anstößigen Code über appDomain.CreateInstanceAndUnwrap() in die AppDomain zu laden und dann die Domain später über AppDomain.Unload() zu entladen. Dies befreit jedoch nicht den nicht verwalteten Speicher, der von dieser Domäne verwendet wird, nur den verwalteten Speicher.

Ich könnte die Anwendung auch in zwei unabhängige Teile aufteilen und nur den Teil mit der nicht verwalteten DLL neu starten. Dies würde jedoch eine große Neukonstruktion bedeuten und wahrscheinlich eine starke Verlangsamung verursachen, da große Datenmengen zwischen diesen beiden Teilen ausgetauscht werden müssten.

Gibt es eine andere Möglichkeit, diese undichte Baugruppe zu zähmen und zu zwingen, ihren Speicher ohne Neustart freizugeben?

    
HugoRune 06.05.2014, 16:58
quelle

2 Antworten

4

Wie Sie es beschreiben, weist die DLL nicht verwalteten Speicher zu. Diese Art von Speicher wird vom Entladen einer App-Domain leider nicht beeinflusst, wie Sie bereits herausgefunden haben.

Sie haben ein paar Optionen, aber ich denke nicht, dass einige von ihnen ansprechend sind:

  1. Sie können die DLL weiterhin in Ihrer Hauptanwendung verwenden. Sie können Ihren Benutzern / Clients mitteilen, dass sie viel Arbeitsspeicher zur Verfügung haben müssen, aber die Anwendung von Zeit zu Zeit neu starten müssen. Wahrscheinlich möchten Sie vor dem eigentlichen Programmabsturz Zustände außerhalb des Arbeitsspeichers erkennen, um den Benutzer sanft dazu anzuregen, ihn neu zu starten, anstatt nur mit einer Ausnahme abzustürzen.
  2. Sie können versuchen, in die Datenstrukturen der DLL zu graben. Wenn sich die DLL tatsächlich ändert (dh es werden neue Versionen herauskommen), würde ich vorschlagen, dass Sie sich stark auf den Autor stützen, um das Speicherleck zu beheben. Dies scheint jedoch unwahrscheinlich, da ich mir ziemlich sicher bin, dass das Leck würde behoben werden, wenn eine neue Version herauskam. Daher könnte es eine a Lösung sein, den Code direkt mit den Innereien dieser DLL zu verknüpfen. Wenn Sie Zugriff auf den tatsächlichen Zeiger haben, der auf den nicht verwalteten Speicher verweist, können Sie ihn möglicherweise manuell freigeben, wie Sie es für richtig halten.
  3. Sie können das Problem auf einen separaten Prozess isolieren. Mehr dazu unten.
  4. Sie könnten die Funktionalität der DLL neu implementieren.

Es könnte eine fünfte oder eine sechste Option geben, aber denken Sie, die obigen 4 decken die Dinge ab, die mir von meinem Kopf gekommen sind.

Über die Isolierung in einen separaten Prozess, hier ist, was ich zuerst versuchen würde:

Ich würde einen Prozess hochfahren und Anfragen an ihn senden, indem ich den schnellsten Intra-Prozess-Kommunikationskanal verwende, den Sie finden können. Pipes scheint gut zu passen, oder Speicher-Mapped-Dateien.

Sie würden dann, in diesem separaten Prozess, die Out-of-Memory-Bedingung, hoffentlich ein bisschen früh, erkennen, so dass Sie dem Hauptprogramm mitteilen könnten, dass es darüber nachdenken sollte, einen Ersatzprozess zu starten.

Der Hauptprozess könnte das dann tun, aber anstatt darauf zu warten, dass dieser andere Prozess vollständig in Gang kommt, könnte er noch ein paar mehr Anfragen an die bald tot werdende Instanz pumpen und es ein bisschen mehr füllen, bevor Sie zu der neuen Instanz wechseln und das alte zum Beenden auffordern.

Dies würde die Ausfallzeit auf Kosten der zeitweiligen Bereitstellung eines zusätzlichen Prozesses während der Übergänge minimieren.

All dies hängt sehr von den tatsächlichen Szenarien ab, die Sie haben. Wenn Sie diese DLL 100 oder 1000 Mal pro Sekunde aufrufen müssen, ist in jedem Fall eine Kommunikation zwischen den Prozessen nicht möglich.

    
Lasse Vågsæther Karlsen 06.05.2014, 17:13
quelle
1

Die DLL weist in Ihrem Prozess nicht verwalteten Speicher zu und gibt sie nicht frei. Das Entladen der Anwendungsdomäne wird in diesem Fall offensichtlich nicht hilfreich sein, da der Speicher innerhalb des Prozesses und nicht innerhalb der Anwendungsdomäne zugewiesen wird.

Um das Speicherleck zu beseitigen, müssen Sie den unfreien Speicher freigeben und es gibt zwei Möglichkeiten, dies zu tun: Beenden Sie den Prozess und lassen Sie das Betriebssystem es tun oder befreien Sie es selbst. Um es selbst zu befreien, müssen Sie den Zugriff auf den Speicher erhalten, indem Sie entweder über die öffentliche Schnittstelle der DLL, durch private Implementierungsdetails der DLL oder durch Überprüfen des Heap des Prozesses erhalten. Es ist wahrscheinlich machbar, aber ich denke, es wird weder Spaß machen, noch einfach und vielleicht nicht einmal robust.

Im Vergleich dazu scheint die Lösung mit zwei Prozessen und dem regelmäßigen Neustart des Lecks einfach und robust zu sein. Ich wäre nicht besorgt über die Leistung, weil Sie zum Beispiel Memory-Mapped-Dateien verwenden können Daten und vermeiden Sie es herum kopieren.

Die einfachste Lösung wäre natürlich, das Speicherleck zu reparieren oder es sogar selbst zu reparieren, indem Sie entweder die Quelle reparieren oder die DLL patchen.

    
Daniel Brückner 06.05.2014 17:26
quelle