Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GC.Collect() and Finalize

Ok, it's known that GC implicitly calls Finalize methods on objects when it identifies that object as garbage. But what happens if I do a GC.Collect()? Are the finalizers still executed? A stupid question maybe, but someone asked me this and I answered a "Yes" and then I thought: "Was that fully correct?"

like image 270
Sandeep Avatar asked Dec 19 '12 14:12

Sandeep


People also ask

What is the difference between Finalize () and garbage collector?

System. gc() forces the garbage collector to run, while the Finalize() method of your object defines what garbage collector should do when collecting this specific object.

What does GC collect () do?

It performs a blocking garbage collection of all generations. All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.

What is finalize in GC?

Finalize method, is used to release unmanaged resources before an object is garbage-collected. If obj does not have a finalizer or the GC has already signaled the finalizer thread to run the finalizer, the call to the SuppressFinalize method has no effect.

What is GC collect () in Python?

Python deletes unwanted objects (built-in types or class instances) automatically to free the memory space. The process by which Python periodically frees and reclaims blocks of memory that no longer are in use is called Garbage Collection.


2 Answers

Ok, it's known that GC implicitly calls Finalize methods on objects when it identifies that object as garbage.

No no no. That is not known because in order to be knowledge a statement must be true. That statement is false. The garbage collector does not run finalizers as it traces, whether it runs itself or whether you call Collect. The finalizer thread runs finalizers after the tracing collector has found the garbage and that happens asynchronously with respect to a call to Collect. (If it happens at all, which it might not, as another answer points out.) That is, you cannot rely on the finalizer thread executing before control returns from Collect.

Here's an oversimplified sketch of how it works:

  • When a collection happens the garbage collector tracing thread traces the roots -- the objects known to be alive, and every object they refer to, and so on -- to determine the dead objects.
  • "Dead" objects that have pending finalizers are moved onto the finalizer queue. The finalizer queue is a root. Therefore those "dead" objects are actually still alive.
  • The finalizer thread, which is typically a different thread than the GC tracing thread, eventually runs and empties out the finalizer queue. Those objects then become truly dead, and are collected in the next collection on the tracing thread. (Of course, since they just survived the first collection, they might be in a higher generation.)

As I said, that's oversimplified; the exact details of how the finalizer queue works are a bit more complicated than that. But it gets enough of the idea across. The practical upshot here is that you cannot assume that calling Collect also runs finalizers, because it doesn't. Let me repeat that one more time: the tracing portion of the garbage collector does not run finalizers, and Collect only runs the tracing part of the collection mechanism.

Call the aptly named WaitForPendingFinalizers after calling Collect if you want to guarantee that all finalizers have run. That will pause the current thread until the finalizer thread gets around to emptying the queue. And if you want to ensure that those finalized objects have their memory reclaimed then you're going to have to call Collect a second time.

And of course, it goes without saying that you should only be doing this for debugging and testing purposes. Never do this nonsense in production code without a really, really good reason.

like image 77
Eric Lippert Avatar answered Sep 27 '22 20:09

Eric Lippert


Actually the answer "It depends". Actually there is a dedicated thread that executes all finalizers. That means that call to GC.Collect only triggered this process and execution of all finalizers would be called asynchronously.

If you want to wait till all finalizers would be called you can use following trick:

GC.Collect(); // Waiting till finilizer thread will call all finalizers GC.WaitForPendingFinalizers(); 
like image 35
Sergey Teplyakov Avatar answered Sep 27 '22 21:09

Sergey Teplyakov