Fix GC live lock issue in rapid UI switching#10856
Conversation
|
There is a memory usage issue in dotnet/dotnet/main when on Linux, copilot can't run right now: |
|
@copilot try again, you encountered an error |
… GRef threshold is reached Co-authored-by: jonathanpeppers <840039+jonathanpeppers@users.noreply.github.com>
Done — commit 59ad351 adds |
There was a problem hiding this comment.
Pull request overview
Addresses a GC live-lock scenario in .NET for Android when rapid UI switching causes a surge of Java proxy allocations and Global References (GRefs), leading to repeated full GCs that can’t make progress because finalizers aren’t draining.
Changes:
- When the GRef “critical” threshold is reached in global reference creation, wait for pending finalizers before forcing a full GC.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
jonathanpeppers
left a comment
There was a problem hiding this comment.
One test failure we can ignore:
Request did not throw cancellation exception; threw: System.AggregateException: AggregateException_ctor_DefaultMessage (Connection failure)
---> System.Net.Http.HttpRequestException: Connection failure
---> Java.Net.ConnectException: Failed to connect to /10.255.255.1:80
In general, I think we should merge this and try it in .NET 11.
Fixes a GC live lock that occurs when an app goes through rapid UI section switching, causing a large number of Java proxy objects to be allocated in a short time.
Root Cause
When GRefs exceed the critical threshold (~46,800),
GC.Collect()is triggered repeatedly but cannot free enough memory because:Gen2GcCallbackwhich runsArrayPool<T>.Sharedtrimming on the Finalizer ThreadFix
In
AndroidRuntime.CreateGlobalReference, addedGC.WaitForPendingFinalizers()beforeGC.Collect()when the GRef threshold is reached (src/Mono.Android/Android.Runtime/AndroidRuntime.cs).This ensures the finalizer queue (including Java proxy object finalizers) drains before the GC runs, giving GRefs a chance to be released and breaking the live lock cycle.
This code path is only triggered when GRefs are already at the critical threshold (
>= gref_gc_threshold), so the synchronous wait is acceptable — the app is already in a degraded state at that point andGC.Collect()was already being called.Original prompt
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.