Ich sehe ein gelegentliches Problem auf Netcore 2.2, bei dem ein gleichzeitiger Gen2-GC nicht im Hintergrund-GC-Thread zu laufen scheint, sondern auf dem Thread, der die Sammlung ausgelöst hat.
Dies wurde bei meiner Windows 10-Entwicklung beobachtet, die eine App in Release-Konfiguration auf der 64-Bit-.NET Core 2.2-Laufzeit mit dem Standard-GC-Profil (Workstation, gleichzeitige GC aktiviert, interaktiver Latenzmodus) ausführte, und ich konnte ein Perfview-Beispiel abrufen des Geschehens:
Wenn ich die GC-Quelle durchschaue, denke ich, dass in diesem Commit ein Problem bgc_thread
zum Zeitpunkt der Thread-Erstellung festgelegt und wird garantiert gesetzt, wenn es in void gc_heap::garbage_collect (int n)
eingecheckt wird. Nach der Änderung wird bgc_thread
jetzt innerhalb des neuen Threads zu Beginn seiner Ausführung gesetzt, was so aussieht, als würde es eine Racebedingung einführen, bei der dieses Feld möglicherweise nicht rechtzeitig gesetzt wird, damit die gleichzeitige GC fortgesetzt werden kann.
ahh, gut gefunden!
@PeterSolMS , @VSadov würde einer von euch bitte einen Blick darauf werfen und
wollte nur darauf hinweisen, dass die hier durchgeführte GC keine BGC mehr ist - sie behandelt es einfach so, als hätten wir den BGC-Thread nicht erstellt, also machen wir einfach eine vollständig blockierende GC; das Ereignis ist irreführend (es steht immer noch Hintergrund), so dass es auch behoben werden sollte, falls wir tatsächlich kein BGC durchführen (der BGC-Thread konnte nicht erstellt werden oder aus einem anderen Grund).
für das Rennen um bgc_thread zu setzen, müssen wir es eigentlich nicht in bgc_thread_stub
, in CreateSuspendableThread
nach dieser Zeile
args.Thread = SetupUnstartedThread(FALSE);
das Thread-Objekt ist bereits verfügbar - die ganze spätere Logik in dieser Funktion ändert nichts an dem Thread, der sowieso erstellt wurde.
Hilfreichster Kommentar
wollte nur darauf hinweisen, dass die hier durchgeführte GC keine BGC mehr ist - sie behandelt es einfach so, als hätten wir den BGC-Thread nicht erstellt, also machen wir einfach eine vollständig blockierende GC; das Ereignis ist irreführend (es steht immer noch Hintergrund), so dass es auch behoben werden sollte, falls wir tatsächlich kein BGC durchführen (der BGC-Thread konnte nicht erstellt werden oder aus einem anderen Grund).