Überwachen meiner .NET-Anwendung im Systemmonitor Ich kann sehen, dass .NET CLR LocksAndThreads / # der aktuellen logischen Threads im Laufe der Zeit stetig ansteigt (derzeit 293), was darauf hinweist, dass der Thread-Stack undicht ist / p>
Ich kann viele Artikel finden, die mir sagen, dass dies das Problem ist, aber nichts, was mir sagt, wie ich die Ursache finde - also wo fange ich an? Kann Windbg mir sagen, wo das Problem liegt?
Dies ist mein Leistungsmonitor über 3 Stunden, der sagt, dass meine aktuellen logischen Threads 150 sind:
Und das ist die Ausgabe des Thread-Fensters, das mir nicht viel sagt, weil ich nicht auf ihre Call-Stacks zugreifen kann - sie sind meistens als [nicht verfügbar] oder [In einem Schlaf, warte oder verbinde] | markiert [Externer Code]:
%Vor%Aktualisierung: Ich habe seitdem den Schuldigen zu einem System.Timers.Timer verfolgt. Selbst wenn dieser Timer bei jedem Elapsed-Ereignis eine leere Methode aufgerufen hat, hat er die logische Thread-Anzahl immer noch unbegrenzt erhöht. Nur das Ändern des Timers in einen DispatcherTimer hat das Problem behoben.
Ich habe alle Timer in meiner Anwendung untersucht, nachdem ich eine große Anzahl gesehen habe, als !dumpheap -type TimerCallback
in Windbg ausgeführt wurde, wie in diese Frage .
Ich würde immer noch gerne wissen, wie ich das über das Windbg-Debugging feststellen konnte und nicht über die Deaktivierungs-Timer / Check-Performance / Repeat-Methode, die mich zur Fehlerbehebung geführt hat. I.e. alles, was mir hätte sagen können, welcher Timer das Problem verursacht hat.
Dies wird normalerweise dadurch verursacht, dass Thread-Pool-Threads hängen bleiben und nicht abgeschlossen werden. Jede halbe Sekunde ermöglicht der Threadpool-Manager einem anderen Thread, mit dem Abbau des Rückstandes zu beginnen. Dies geht weiter, bis es die maximale Anzahl von Threads erreicht, wie von ThreadPool.SetMaxThreads () festgelegt. Standardmäßig eine große Zahl, 1000 auf einem 4-Core-Rechner.
Verwenden Sie Debug + Windows + Threads, um sich die laufenden Threads anzusehen. Ihr Call-Stack sollte es offensichtlich machen, warum sie blockieren.
Probieren Sie alle lang andauernden Operationen (100+ ms Datenbankaufrufe, Festplatten- oder Netzwerkzugriff) aus, um asynchron zu laufen.
Verwenden Sie async / erwarten primitive Anweisungen in .NET 4.5.
Thread-Pool erhöht die Thread-Nummer, wenn kein Thread verfügbar ist, wenn eine in die Warteschlange gestellte Task aus der Thread-Pool-Warteschlange abgerufen wird. Wenn die Tendenz auf dem Server so bleibt, enden Sie wahrscheinlich mit einem Thread-Pool-Hunger. Wenn die Thread-Pool-Warteschlange voller Aufgaben ist, lehnt .NET mehr Anfragen ab, so dass Sie an der Grenze der Skalierbarkeit Ihrer Anwendung sind.
Mit der Anweisungaway wird in Ihrer Anwendung ein Workflow generiert, der den Hauptthread freigibt. Nachdem der lange Ausführungsvorgang abgeschlossen ist, wird eine neue Aufgabe in den Threadpool eingereiht, sodass die Anwendung automatisch fortgesetzt werden kann. Das Freigeben und Recyceln von Threads auf diese Weise hält die Anzahl der aktuellen logischen Threads auf einem minimalen Level, wodurch das Verhungern und weitere Kontextwechsel zwischen Threads verhindert werden.
Auch in .NET 4.5 steuert ein neuer Algorithmus die Kosten / Nutzen neuer Thread-Erstellung innerhalb des Thread-Pools, wobei ein vernünftiger Zusammenhang zwischen Leistungssteigerung und Kontextwechsel besteht, wenn die Tendenz zunimmt. Dies ist ein zusätzlicher Vorteil, den Sie erhalten, wenn Sie zu 4.5 wechseln, wenn Sie dies noch nicht getan haben.
Der erste Schritt besteht also darin, Ihre lang andauernden Operationen zu identifizieren und sie dann asynchron zu machen.
Sie können dies überprüfen, indem Sie # der aktuellen logischen Threads mit anderen Leistungsindikatoren korrelieren (Datenbank-Clientverbindungen, Datenträger-E / A-Lesevorgänge usw.). Wenn der erste Anstieg bei den anderen zunimmt, sind Sie wahrscheinlich sicher, dass dies das Problem ist. Überprüfen Sie auch, wie lange die Vorgänge dauern. 100 ms ist ein gutes Maß, um zu sagen, dass Ihre Operation in einem allgemeinen Sinne läuft.
Hoffe diese Hilfe.
Tags und Links memory-leaks .net multithreading c++-cli