GC.Collect () does not collect right away?

During the discussion in the chat, I wrote this console application.

the code:

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(); } } 

Result:

 Collecting... Done Unhandled Exception: System.Exception: Exception of type 'System.Exception' was thrown. at SomeClass.Finalize() 

I expected the application to crash before Done printed.

I don’t care how to do it. My question is: why is this not so?

+4
source share
4 answers

Objects with finalizers cannot be collected as part of a single garbage collection procedure. Such objects are moved to the f-reachable queue and remain there until finalizers are output. Only then can they be collected in garbage.

The following code is better, but you should not rely on it anyway:

 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); 

Also, throwing exceptions in the finalizer seems too cruel for me, even for testing purposes.

In addition, there is an interesting side effect of finalizers: an object with a finalizer can still "resurrect" itself (effectively prevent garbage collection) if it stores the this link in finalizer (assigns it some static variable).

+12
source

Have you read the documentation ?

Use this method to try to recover all inaccessible memory.

This is not a team, this is a request that may or may not work as you would like. In any case, this is not a good idea (sometimes as a result of some process many, many small, short-lived objects are created, and in this case it may be useful to call GC.Collect , but this is rare).

Since you don’t think you are trying to solve a real problem and instead look at the GC, this is the best advice I can offer.

+6
source

In the most common garbage collector implementations, the managed user code cannot be run during the garbage collection cycle. Finalize methods are counted as user code. Although it is theoretically possible for the system to freeze all other user code when Finalize methods are executed, this will increase the apparent cost of garbage collection in multi-core systems, as well as increase the likelihood of a deadlock. To avoid these problems, the system does not run Finalize methods as part of the garbage collection, but instead builds a list of objects that must have their Finalize methods (the list is called a "freachable queue"). The list itself is considered the root link, so any object referenced by the object in the freachable queue will be considered firmly rooted, at least until the system extracts the roaming object from the queue, starts it Finalize and discards the link.

Microsoft's early documentation of the final revision is very confusing because it assumes that objects to which final objects can be bound may not exist when these methods are run. In fact, all such objects are guaranteed to exist; which is unclear whether they will already have their Finalize methods.

+2
source
  • GC.Collect () places those objects that are not referenced, and has a finalizer method for the finalizer queue.
  • it will clear the finalizer queue with a call to complete the methods.

If the above two points are clear, then your code contains a reference to SomeClass in the static method. This means that it is still alive until the main method of the program is executed.

If you want your application to crash before printing "done", first hide the SomeClass object and then call GC.Collect. He will put your object in the finalizer queue, but again his GC will wish when to clear this queue. If you want the GC to clear this queue and start the finalizer, call GC.WaitForPendingFinalizers (). Your thread will wait for your finalizer to be called, and it will continue. I changed your code to the desired output. Instead of throwing an exception, I typed the expression in the 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..."); } } 
0
source

Source: https://habr.com/ru/post/920732/


All Articles