Wir müssen verstehen, welcher Teil unseres Codes (oder Dritter, wahrscheinlich CLR selbst) zum Einbetten von Ganzzahlen führt.
Wir haben eine ziemlich große Anwendung, wo wir eine hohe Zuteilungsrate von System.Int32
Instanzen beobachten. Mit Hilfe von Memory Profiler sehen wir eine kleine Anzahl von langen vorhandenen Int32
Instanzen (18, um genau zu sein) und 20-25 Tausend% Int32
Allokationen pro Sekunde. Alle diese Objekte werden als Gen0-Objekte erfasst, das System hat keine Speicherlecks und kann für lange Zeit ausgeführt werden. Wenn ein Speicher-Snapshot erstellt wird, wird GC vor dem Snapshot ausgeführt, sodass Snapshot keine Spuren dieser "temporären" Objekte enthält.
All unser Code wurde speziell geschrieben, um das Boxen zu eliminieren, wann immer es möglich ist, und "per Design" sollen wir überhaupt keine Boxen sehen. So vermuten wir, dass es in unserem Code einige nicht eliminierte vergessene Boxen gibt oder Boxen, die durch Komponenten von Drittanbietern und / oder den CLR-Typ selbst verursacht werden.
Das System wird mit VS2008 kompiliert und verwendet .Net 3.5 (Messungen wurden sowohl im Debug- als auch im Release-Build mit dem gleichen Verhalten durchgeführt).
Wie können wir (mit windbg, VS2008, Memory Profiler, AQTime oder einem anderen kommerziell erhältlichen Produkt) erkennen, warum Boxen passiert?
Eine meiner Lieblingsanwendungen ist der CLR Profiler, der Ihnen das liefert, wonach Sie suchen. Er wird Ihre gesamte Anwendung mit den verschiedenen Generationen abbilden. Es ist ein kostenloser Download von Microsoft und es ist extrem leistungsstark und einfach zu bedienen. Ich habe auch einen Link für die Verwendung angegeben. (CLR Profiler Download) (So verwenden Sie CLR Profiler)
Es ist überraschend, dass Methoden der DateTime-Klasse ToLocalTime / ToUniversalTime zum Boxen führen.
Unsere Anwendung (Anwendungsserver) wurde kürzlich so modifiziert, dass sie nur noch in UTC "intern" funktioniert (um Veränderungen der Tageszeit zu bewältigen). Unsere Client-Codebasis blieb zu 99% lokal.
Der Anwendungsserver konvertiert (falls erforderlich) lokale Zeiten in UTC-Zeiten vor der Verarbeitung, was bei jeder zeitbezogenen Operation zu einem Box-Overhead führt.
Wir werden in Erwägung ziehen, diese Operationen "im eigenen Haus" ohne Boxen umzusetzen.
Haben Sie eine statische Analyse Ihres Codes vorgenommen? Vielleicht kann NDepend Ihnen dabei helfen, die Methoden und Typen zu finden, die Werte für Boxing und Unboxing enthalten.
Eine Testversion von NDepend ist frei verfügbar. Es lohnt sich also, die Assemblys, sowohl Ihre als auch die von Drittanbietern, zu analysieren.
Ein sehr niedriger, aber überraschend effektiver Ansatz besteht darin, einen Debugger anzuhängen und immer wieder auf Pause zu drücken und zu sehen, wo das Programm aufhört.
Wenn Sie eine ausreichende Menge an Zeit zuweisen, um eine große Menge an GC-Aktivität auszulösen, haben Sie eine gute Chance, den Code, in dem die Boxing-Zuweisung stattfindet, einzubrechen.
Dies hat den Vorteil, dass Sie keine neuen Tools benötigen (vorausgesetzt, Sie haben eine anständige IDE oder einen Debugger)
Ich glaube GlowCode kann berichten, wo das Boxen von Werttypen stattfindet, obwohl Sie die Optionen durchforsten müssen, um herauszufinden, wie mach es an.
Boxen und Unboxing-Vorgänge können durch statische Analyse Ihres Codes erkannt werden. Suchen Sie nach fxcop-Regeln.
Ein Profiler kann Ihnen vielleicht auch helfen, da so viele Zuweisungen pro Sekunde sicherlich viel Overhead verursachen.
Viel Glück und halten Sie uns über Ihre Ergebnisse auf dem Laufenden.