-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Finalizer no longer called in .NET Core 2.0 after GC.Collect / GC.WaitForPendingFinalizers #9328
Comments
The behavior you are seeing is not a bug. https://github.com/dotnet/coreclr/issues/5826#issuecomment-226574611 explains the details. Duplicate of #6157 |
Interesting. I read your comment and the one thereafter, but I'm still not sure I completely understand why my finalizer is never called in .NET Core 2.0 when running in Debug mode (but it does get called in Release mode which I hadn't realized until reading that thread), but so this is what I gathered as to why my test is failing on .NET Core 2.0 in Debug mode:
What eludes me is how come the finalizer in my test is never called, even when I keep the program alive (by awaiting another thread that performs an infinite loop). Could the answer lie in the way the JIT emits the assembly language output in debug mode? |
It's not that the finalizer isn't called for an object that's become unreachable: it's that the object isn't becoming unreachable and thus isn't collected and isn't finalized. The lifetime of the object is getting extended in the method, with a temporary keeping it alive. Try creating the object instead in a non-inlined helper. |
That makes a lot of sense. However I'm unsure how to create an object from a non-inlined helper. I mean, I thought I knew I did, but when I try it still fails when built in Debug mode. Here's what I tried: [TestMethod]
[Description("Asserts that an un-rooted object graph will be garbage collected.")]
public void GarbageCollectionTest01()
{
var spy = new Spy();
CreateFoo(spy);
GC.Collect(0, GCCollectionMode.Forced, blocking: true);
GC.WaitForPendingFinalizers();
Thread.Sleep(10);
Assert.IsTrue(spy.FinalizerIsCalled);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private Foo CreateFoo(Spy spy)
{
return new Foo(spy);
} |
@sfmskywalker, my point of suggesting a non-inlined helper was to keep the object out of the frame in which you're then forcing a collection. The moment you return the object from the helper into the calling frame, you potentially enable the JIT to extend the lifetime of the object past that garbage collection. What is it you're trying to do? |
Now I see. You're right; when I instantiate Foo in the non-inlined helper without returning it to the caller, its finalizer does get called. This small unit test originated from a slightly different one in one of my projects where I wanted to test whether the GC would reclaim an object even if there would be a circular reference between Foo and Bar. When this unit test started failing after upgrading to .NET Core 2.0, I started bringing that test down to its bare minimum to find the root cause of the issue. But, as you and @jkotas point out, the problem was my incorrect assumption about how things were supposed to work. Thank you both for helping me get a much better understanding, much appreciated! |
I already reported this issue here, but realized this repo might be more appropriate. If not, I'll close it. Otherwise I'll close the other.
Finalizer no longer called in .NET Core 2.0 after GC.Collect / GC.WaitForPendingFinalizers
As of .NET Core 2.0, an object's finalizer is no longer called when calling
GC.Collect
andGC.WaitForPendingFinalizers
.General
To be clear: the following code works as advertised in .NET Framework 4.7 and earlier; .NET Core 1.1 and earlier; but not in .NET Core 2.0:
Unit test output:
To demonstrate the issue, I created a unit test project for the following frameworks which all share the same .cs file:
GarbageCollectionTests.zip
The text was updated successfully, but these errors were encountered: