Laden...

Memory Leak trotz Dispose, nullen usw.

Erstellt von ThomasE. vor 10 Jahren Letzter Beitrag vor 10 Jahren 2.393 Views
T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 10 Jahren
Memory Leak trotz Dispose, nullen usw.

Hallo nochmal,

es geht hier um ein Programm, welches Daten aus dem ActiveDirectory, in eine Datenbanktabelle schreibt.

Dieses Programm steckt in einer DLL, welche wiederum von einem Viewer und auch von einem Service aus verwendet wird.

Im Viewer steigt der Speicherverbrauch nach einer Anwendung dementsprechend an, wird aber nach sämtlichen Speicher-Freigaben nicht wieder weniger...

Bei einem weiteren Aufruf, steigt der Speicherverbrauch um ein minimales zum ersteren weiter an, dieses wiederholt sich bei jedem weiteren Aufruf..

Bei der Ausführung als Server, ist der Anstieg nach jedem Aufruf soagr noch höher, als im Viewer.

Das alles, obwohl folgendes immer gemacht wird:
Aufruf von Dispose() und setzen von null bei
DirectoryEntry, DirectorySearch, Dictionary, List, DataTable
bei DirectoryEntry wird sogar vorerst noch Close() aufgerufen.

Zusätzlich werden alle Referenzen (nur 1ne) zu der jeweiligen DLL nach dem Beenden eines Aufrufs auf null gesetzt.

Mir ist durchaus bewußt, daß es schwer ist, ohne Code etwas zu beurteilen, da müßte man fast die ganze DLL reinstellen..

Mir geht es in erster Linie nur darum zu fragen, ob wer aus dem Stehgreif mir einen Tip geben könnte, wo ich weiter suchen kann ?

Ist das Verhalten des GarbageCollectors in einem Service anders als in einer normalen Anwendung ?

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo ThomasE.,

wie in [erledigt] Memory leak im Loop [=> vermutlich Scheinproblem, trotzdem Besserung durch StringBuilder] würde ich vermuten, dass du gar kein Memory Leak hast, sondern nur vom GC etwas anderes erwartest, als er tatsächlich tut. Insbesondere gibt der GC den Speicher nicht sofort nicht mal zeitnah frei, sondern oft erst, wenn er anderweitig benötigt wird. Außerdem ist der Taskmanager nicht geeignet, um herauszufinden, ob der GC bereits Speicher zur Neunutzung innerhalb der Anwendung freigegeben hat. Dazu braucht man einen entsprechenden Memory Profiler.

Ich kann also nur den Tipp aus dem anderen Thread wiederholen: Informiere dich erstmal über die Arbeitsweise und Besonderheiten des GC und benutze die passenden Werkzeuge und erst wenn du dann echte Anhaltspunkte für ein Memory Leak hast und uns mitteilst, können wir sinnvoll weitereden.

herbivore

16.834 Beiträge seit 2008
vor 10 Jahren

Dass Du Dispose UND Close aufrufst zeigt irgendwie, dass Du nicht weißt, wie der Code funktioniert - denn Close ruft intern Dispose(true) auf und tut nichts anderes 😉
Wenn Du using() an den passenden Stellen verwendest brauchst Du Dich um Dispose gar nicht mehr (selbst) kümmern.

Prinzipiell ist der PrincipalContext sicherer als DirectoryEntry mit dem Unterschied, dass ersterer mit einem (quasi) DOM arbeitet.

Was im anderen Thread zu kurz kommt: verwende einen Profiler.
Der kann dir wirklich sagen, welcher Programmteil Speicher verbraucht und welche nur reserviert ist. Letzten Endes ist es "normal", dass eine Oberfläche mehr speicher benötigt als ein Service, der keinerlei GUI Elemente hat.
Wahrscheinlich ist Dir das Verhalten - wie herbivore sagte - einfach nicht bewusst.

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 10 Jahren

Ok, vielen Dank, werd mir das nochmal genau anschauen.

Dass Du Dispose UND Close aufrufst zeigt irgendwie, dass Du nicht weißt, wie der Code funktioniert - denn Close ruft intern Dispose(true) auf und tut nichts anderes 😉

Doch doch, war mir schon klar das unter Close() automatisch Dispose() aufgerufen wird, nur wollt ich zum testen auf Nummer sicher gehen.

Das using verwende ich, halt nicht überall, könnte dies eventuell noch überarbeiten.

Das ist mir klar das eine Grafische Anwendung mehr Speicher benötigt, das habe ich nie angedeutet, sondern das die Verwendung als Service, mehr Speicher ansammelt als in der Grafischen Anwendung.

Das mit dem Profiler werd ich mir noch genauer anschauen, danke !

Schöne Grüße

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

W
872 Beiträge seit 2005
vor 10 Jahren

Allgemein würde ich empfehlen, den Process Explorer zu benutzen, da Du dort sehen kannst, wieviele Elemente in welcher Generation des Garbage Collectors sind und wann der GC welche Generation abarbeitet.
Ein Memory Leak ist nur, wenn die Generation 2 Heap Size/Collections steigt.
Du siehst das für den Prozess, indem Du mit der rechten Maustaste "Properties" und dann ".NET Performance" auswählst.
Der Process Explorer hat gegenüber Profilern den Vorteil, dass die Performance nicht beeinflusst wird und das er umsonst ist. Dafür musst Du dann selber im Code suchen, wenn es wirklich ein Leak gibt.

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 10 Jahren

So, wie es aussieht, hab ich meinen Fehler gefunden !

Und oft ist es so, daß die Antwort schon in der Frage steckt !!

es geht hier um ein Programm, welches Daten aus dem ActiveDirectory, in eine Datenbanktabelle schreibt.

Das alles, obwohl folgendes immer gemacht wird:
Aufruf von Dispose() und setzen von null bei
DirectoryEntry, DirectorySearch, Dictionary, List, DataTable

Es wird ja ebenfalls OdbcConnection, OdbcCommand und OdbcDataReader verwendet !

Seltsamer Weise hatte ich die OdbcConnection in einem using-Block vorgesehen aber die anderen Objekte nicht und hatte diese auch nicht freigegeben ! 🙄 8o
Der Profiler hatte diese Sache auch als MemoryLeak festgestellt.

Dank dem Profiler, bin ich ziemlich schnell auf das Ergebnis gekommen !

Und wieder dazu gelernt, immer ordentlich zu arbeiten, egal ob Streß oder nicht, da stellt man sich immer nur selbst ein Bein !

Hatte zusätzlich nach dem Ende der Abarbeitung,

GC.Collect();

einmalig eingebaut, damit während der 1 Tages Pause zwischen den Aufrufen, nicht die ganze Zeit der gesamte Speicher reserviert bleibt.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

16.834 Beiträge seit 2008
vor 10 Jahren

Ähm.. GC.Collect() wird keine Objekte weg hauen, die nicht sauber freigegeben sind. Egal ob manuell aufgerufen oder nicht.
Daher: Finger weg davon, wenn man nicht weiß, was man tut.

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 10 Jahren

Das ist mir klar.

Soweit hatte ich das schon begriffen das der GC nur saubere Elemente wieder freigibt... hatte ich auch nie anders behauptet.

Wie ich schon schrieb, daß ich meinen Fehler ausgebessert hatte.

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

M
171 Beiträge seit 2012
vor 10 Jahren

Also um es nochmal zusammen zu fassen, auch wenn es bereits gesagt wurde:

1.) Mit dem Taskmanager findet man keine Memory Leaks. Man findet mit dem Taskmanager nicht mal heraus, ob man ein Memory Leak hat oder nicht.

2.) GCCollect ist in 99% aller Fälle eine sehr schlechte Idee, und ich glaube, in Deinem Fall ist das auch eher kontraproduktiv.

T
ThomasE. Themenstarter:in
461 Beiträge seit 2013
vor 10 Jahren

Ich verwende das GC.Collect() ganz am Ende der Abarbeitung, danach läuft bis am nächsten Tag gar nichts mehr.

Kontraproduktiv wäre es nur dann, wenn ich es öfters verwende und dauernd nach jedem Furz aufrufe. 😃

Das tue ich nicht, weil ich weiß, daß es absolut sinnlos wäre. Schon alleine wegen der Performance...

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

P
1.090 Beiträge seit 2011
vor 10 Jahren

Nun im 2.0 Framework war der GC noch selbst optimierend und es gab den Hinweis des GC Entwicklers Collect nicht aufzurufen, da sonst die Optimierungen nicht greifen.

Ich glaub, das gilt immer noch.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern