Runtime: Concurrent GC fails to run concurrently

Created on 9 Aug 2019  路  3Comments  路  Source: dotnet/runtime

I'm seeing an occasional issue on netcore 2.2 where a concurrent Gen2 GC seems to not run on the background GC thread, instead running on the thread that triggered the collection.

This was observed on my Windows 10 development running an app in Release configuration on the 64-bit .NET Core 2.2 runtime with the default GC profile (workstation, concurrent GC enabled, interactive latency mode), and I was able to grab a perfview sample of the occurence:

blockingConcurrentGC

Looking through the GC source, I think there may be an issue introduced in this commit. Before the change, bgc_thread would be set at the time of thread creation, and would be guaranteed to be set by the time it's checked in void gc_heap::garbage_collect (int n). After the change, bgc_thread is now set within the new thread at the start of it's execution, which seems like it would introduce a race condition where that field may not be set in time for concurrent GC to continue.

area-GC-coreclr question

Most helpful comment

just wanted to point out that the actual GC done here is no longer a BGC - it just treats it as we failed to create the BGC thread so we are simply doing a full blocking GC; the event is misleading (it still says Background) so that should also be fixed in case we fail to actually do a BGC (failed to create the BGC thread or for any other reason).

All 3 comments

ahh, good find!
@PeterSolMS, @VSadov would one of you please take a look and make a fix?

just wanted to point out that the actual GC done here is no longer a BGC - it just treats it as we failed to create the BGC thread so we are simply doing a full blocking GC; the event is misleading (it still says Background) so that should also be fixed in case we fail to actually do a BGC (failed to create the BGC thread or for any other reason).

for the race of setting bgc_thread, we actually don't need to to set it in bgc_thread_stub, in CreateSuspendableThread after this line

args.Thread = SetupUnstartedThread(FALSE);

the Thread object is already available - all the later logic in this function doesn't change the Thread that got created anyway.

Was this page helpful?
0 / 5 - 0 ratings