Reputation: 44326
In the course of a discussion in chat, I wrote this console application.
using System;
class Program
{
static void Main(string[] args)
{
CreateClass();
Console.Write("Collecting... ");
GC.Collect();
Console.WriteLine("Done");
}
static void CreateClass()
{
SomeClass c = new SomeClass();
}
}
class SomeClass
{
~SomeClass()
{
throw new Exception();
}
}
Collecting... Done
Unhandled Exception: System.Exception: Exception of type 'System.Exception' was
thrown.
at SomeClass.Finalize()
I would have expected the app to crash before Done
was printed.
I don't care much about how to make it. My question is, why doesn't it?
Upvotes: 5
Views: 7909
Reputation: 2084
If the above two points are clear, then your code holds a reference to SomeClass in a static method. That means it is still alive until the Program's main method is executing.
If you want your app to crash before printing 'done', then first nullify your SomeClass object and then call GC.Collect. It will put your object in finalizer queue but again its GC's wish when to clear out that queue. If you want GC to clear out that queue and call finalizer, then call GC.WaitForPendingFinalizers(). Your thread will wait until your finalizer is called and it will then proceed. I modified your code for desired output. Instead of throwing exception I printed a statement in finalizer.
class Program
{
static void Main(string[] args)
{
CreateClass();
Console.Write("Collecting... ");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Done");
Console.ReadLine();
}
static void CreateClass()
{
SomeClass c = new SomeClass();
c = null;
}
}
class SomeClass
{
~SomeClass()
{
Console.WriteLine("Finalized...");
}
}
Upvotes: 0
Reputation: 81159
In the most common garbage-collector implementations, no managed user code can be run during a garbage-collection cycle. Finalize
methods count as user code. Although it would be theoretically possible for the system to freeze all other user code while Finalize
methods execute, this behavior would increase the apparent cost of garbage collection on multi-core systems and also increase the likelihood of deadlock. To avoid these issues, the system does not run Finalize
methods as part of garbage collection, but instead builds a list of objects that need to have their Finalize
methods run (the list is called the "freachable queue"). The list itself is considered a rooted reference, so any object which is referred to by an object in the freachable queue will be considered to be strongly rooted at least until such time as the system retrieves the freachable object from the queue, runs its Finalize
method, and discards the reference.
Microsoft's early documentation regarding finalization is very confusing, since it suggests that objects to which finalizable objects hold references might not exist when those methods run. In fact, all such objects are guaranteed to exist; what is uncertain is whether they will have already had their Finalize
methods run.
Upvotes: 3
Reputation: 34407
Objects with finalizers cannot be collected within a single garbage collection procedure. Such objects are moved to f-reachable
queue, and remain there until finalizers are called. Only after that they can be garbage-collected.
Following code is better, but you should not rely on it anyway:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Also, throwing exceptions in finalizer seems too brutal for me, even for testing purposes.
Also, interesting side-effect of finalizers: an object with finalizer can still 'resurrect' itself (effectively prevent garbage collection of itself), if stores this
reference in finalizer (assigns it to some static variable).
Upvotes: 12
Reputation: 124642
Did you read the documentation?
Use this method to try to reclaim all memory that is inaccessible.
It is not a command, it is a request, which may or may not work out as you would like. This is not often a good idea anyway (sometimes many, many small, short-lived objects are created as a result of some process, in which case it may be beneficial to call GC.Collect
, but this is rare).
Since it doesn't seem like you are trying to solve a real problem and are instead toying around with the GC this is the best advice I have to offer.
Upvotes: 6