[c#] benutzten Nicht verwalteten Speicher anzeigen

Passer

Erfahrenes Mitglied
Gibt es eine Möglichkeit, sich bei einem C# Programm den benutzten nicht verwalteten Speicher anzeigen zu lassen?

Ich habe in einem grösseren Projekt ein kleines Speicherleck und bräuchte da solch eine Funktionalität.

Ich nehme an, dass hier und da ein
Marshal.FreeCoTaskMem

vergessen wurde und nun will ich sehen, welche Komponenten das Speicherleck verursachen.

MfG
Christoph
 
Tool hierfür kann ich dir jetzt keines vorschlagen. Aber sollte dies nicht durch einen manuellen Test recht schnell auffallen?

Bzw. lassen sich solche Dinge durch das Erstellen von Tests relativ schnell abfackeln ...
 
Schade, ich dachte, ich kann auf diese manuellen Taskmanager Guck Orgien verzichten...

Nun sei eine kleine Frage hinterher geschoben...

Kann es sein, dass sich die .NET VM bspw in Extremtests (Ich erzeuge Megabyteweise Bytearrays, die ich durch verschiedenste Funktionen jage; und das alle 5ms) jeweils soviel Arbeitsspeicher reserviert, wie grad frei ist und erst, wenn nichts mehr da ist, den Garbage Collector einsetzt?

Ich habe nämlich beobachtet, das bei ca 500 Speichernutzung diese danach wieder stark zurückfällt, obwohl ich alle 10 Sekunden GC.Collect() aufrufe (was wiederum keinen Effekt zu haben schein)
 
Naja, grundsätzlich reserviert die VM gleich mal relativ viel Speicher, um entsprechende Performance zu garantieren. Wird dieser Speicher von anderen Anwendungen benötigt, wird da brav zurückgegeben. (Siehe auch das Minimieren von Anwendungen).

Was GC.Collect() betrifft: Der .NET Garbage Collector arbeitet in mehreren Stufen (mehrere Generationen von Objekten). Bei einem Aufruf von GC.Collect() wird ein Full-Collect durchgeführt, d.h. sämtliche Generationen werden durchlaufen. Das hat nun zur Folge, dass es a) sehr aufwendig ist und daraus resultierend b) lange dauert. Wird nun vom GC nichts entfernt, dann sind deine Objekte noch referenziert und werden daher nicht entfernt.
 
Code:
DllImportAttribute("kernel32.dll", EntryPoint="SetProcessWorkingSetSize", ExactSpelling=true, CharSet=CharSet.Ansi, SetLastError=true)] 
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize); 

public static void RealMemory() 
{ 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
if (Environment.OSVersion.Platform == PlatformID.Win32NT) 
{ 
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); 
} 
}
 
Cool, da ist die Antwort ja schneller, als die Frage, wie man einem .NET Programm den zu nutzenden Speicher limitiert ;)

liege ich da richtig?
 
Nein:)
Jedem Prozess stehen immer 4GB zur Verfügung - mehr Info. Wirklich vergeben werden die aber nur bei Bedarf. Wenn du z. B. eine Anwendung hast, die 4 GB wirklich braucht und nur 200MB im Arbeitspeicher frei sind, dann wächst die pagefile.sys Datei auf der Festplatte um 3,8 GB.

Zuerst die Antwort auf deine erste Frage:
'zeigt die Speichernutzung wie im Taskmanager
TextBox1.Text = Environment.WorkingSet.ToString;

Taskmanager und der obige Code zeigen wie viel Speicher (von den 4GB) sich tatsächlich im RAM befindet. Wenn du das manuell begrenzen würdest:
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, 100, 500);
dann müsste Windows Teile deines Programs in der pagefile.sys speichern, obwohl es Platz im RAM gibt. Das gilt auch für ein Speicherleck - die pagefile Datei wird immer größer.

So gesehen hat der Code in meinem vorherigen Post nur kosmetische Wirkung. So kann man nicht mehr behaupten, dass eine C++ Anwendung nur 1 MB benötigt, während dieselbe Anwendung geschrieben im .NET - 15MB. Windows und das Framework sind 'Freunde' und Windows beschenkt es mit größeren Stücken von RAM. Wenn aber Arbeitspeicher woanders gebraucht wird, wird er innerhalb von Millisekunden freigegeben.

Das Minimiren ist ein alter Trick, um das zu illustrieren. Dabei wird die beschriebene SetProcessWorkingSetSize Funktion benutzt.

Wie Norbert Eder schon sagte, GC.Collect manuell aufzurufen ist unnötig. Wenn der freie Arbeitspeicher zu knapp wird, kommt er sowieso öfters vorbei.

Es reicht, wenn man immer die Dispose() Methode benutzt; der GC kümmert sich dann um die Freigabe beim nächsten Besuch.
 
Zurück