Garbage collection Guarantees - c#

What guarantees are the for the garbage collector?
From my research I have managed to find:
If there is still a reference to the memory it will not be garbage collected
If there is no reference:
When it is GC is non deterministic
When the GC kicks in the finalizer will be run before memory is released.
There is no guarantee about the order of Finalizers (so do not assume parent will be run before child).
But what I really want to know is:
Is there a guarantee that all memory will eventually be garbage collected and the finalizer (destructor) run on the object (assuming the program exited nicely). For example an application with no memory pressure when it eventually exits will it force the GC to go find all objects and make sure the finalizer (destructor) is called (including static member variables)?
I did find a quote on this page:
http://www.c-sharpcorner.com/UploadFile/tkagarwal/MemoryManagementInNet11232005064832AM/MemoryManagementInNet.aspx
In addition, by default, Finalize methods are not called for unreachable objects when an application exits so that the application may terminate quickly.
But I am not sure how authoritative this quote is.
I also found documentation on:
CriticalFinalizerObject

Is there a guarantee that all memory
will eventually be garbage collected
and the finalizer (destructor) run on
the object (assuming the program
exited nicely).
No. From the Object.Finalize documentation it is clear that finalizers may not be invoked if
Some other finalizers don't finish properly:
Another finalizer blocks indefinitely
(goes into an infinite loop, tries to
obtain a lock it can never obtain and
so on). Because the runtime attempts
to run finalizers to completion, other
finalizers might not be called if a
finalizer blocks indefinitely.
Some other finalizers create more
finalizable objects, making it
impossible to finalize all
finalizable objects:
The runtime continues to Finalize
objects during shutdown only while the
number of finalizable objects
continues to decrease.
Some other finalizers throw exceptions:
If Finalize or an override of Finalize
throws an exception, and the runtime
is not hosted by an application that
overrides the default policy, the
runtime terminates the process and no
active try-finally blocks or
finalizers are executed. This behavior
ensures process integrity if the
finalizer cannot free or destroy
resources.
That being said, there are more reasons why you wouldn't want to use finalizers unless strictly necessary.
They slow down the garbage collector
(even making it possible to slow it
down so much that memory is not
reclaimed as fast as it is used up).
They run on another thread, bringing
multi-threading issues into play.
They're not executed in a
deterministic order.
They can resurrect objects which were
already finalized (and which won't be
finalized again unless explicitly
re-registered for finalization).

The only time you should write a finalizer is when you are building a type to handle a new kind of unmanaged resource. For example, a data access layer that uses Sql Server in a business app doesn't need a finalizer anywhere, even though there are unmanaged database connections involved, because the basic SqlConnection class will already finalize those connections if needed. But if you're building a brand new database engine from scratch that has connection limits similar to sql server's and are implementing the ado.net provider for it, that connection type should implement a finalizer to be as sure as possible that your connections are released.
But you don't get any guarantees beyond what happens when a process ends.
Update:
Given this context:
I am having a discussion with a collegue over a code review I did of his code. He insists that the destructor is guranteed to be called on an object. I disagree (but am not sure) and would prefer the use of IDisposable.
You are right to criticize the use of a destructor/finalizer. As I said above, you should only use them when working with an unmanaged resource that is genuinely new. Not just that instance of the resource, but the kind of resource you are working with.
For code that wraps "normal" unmanaged resources (things like SqlConnection, TcpClient, etc), IDisposable is a better choice. Then you know the resource will be cleaned up as soon as Dispose() is called rather than needing to wait for the type to be collected. If no one calls Dispose() (which is likely your colleague's concern), by the time your new type can be collected the instance of the original type for the unmanaged resource you are wrapping should be able to be collected as well, and it's finalizer will release the resource.
The main thing you need to bring to the table is that the finalizer cannot be called until the object is collected. You have to wait on the garbage collector, meaning you may be holding the resource open even longer. IDisposable allows you to release it right away. Of course you could do both, but that doesn't sound like what's going on here, and if you do have both you have to be careful not to conflict with the original type's finalizer or you could cause unwanted and harmful exceptions. And really, your own finalizer implementation is just redundant here and adds needless complexity.
Finally, I have to take issue with this statement:
If there is still a reference to the memory it will not be garbage collected
There can be references to an object and it will still be collected. What matters is if the object is reachable: are any of the references to the object rooted. For example, you may have a list with several objects in it. The list goes out of scope. Obviously there is still a reference to all of the objects in the list, but they can still all be collected in the first pass of the GC because the reference is no longer rooted.

1.6.7.6 of the Spec says:
1.6.7.6 Destructors
A destructor is a member that implements the actions
required to destruct an instance of a
class. Destructors cannot have
parameters, they cannot have
accessibility modifiers, and they
cannot be invoked explicitly. The
destructor for an instance is invoked
automatically during garbage
collection.
The garbage collector is
allowed wide latitude in deciding when
to collect objects and run
destructors. Specifically, the timing
of destructor invocations is not
deterministic, and destructors may be
executed on any thread. For these and
other reasons, classes should
implement destructors only when no
other solutions are feasible.
The
using statement provides a better
approach to object destruction.
So no, it's not guaranteed they are called.

The only time that a finalizer won't be invoked at all is if an AppDomain is forcibly unloaded.
In general, you don't need to worry about it.

There is no guarantee.
There might be a guarantee if your process terminates nicely for some definition of nicely. But there are so many things not nice that can happen:
power failure
process terminated in a 'hard' or 'forced' way
unmanaged thread throwing calling OS exit() function or throwing an exception
call to System.Environment.FailFast, which does:
MSDN: "Terminates a process but does not execute any active try-finally blocks or finalizers."

Related

Does an object with a pending finalizer need to be collected by the GC more than one time?

I am reading the "Disposal and Garbage Collection" chapter of book C# 8.0 in a Nutshell. When it comes to finalizers, it says:
The GC identifies the unused objects for deletion, those without
finalizers are deleted immediately, those with pending finalizers are
kept alive and are put onto a special queue. When the garbage
collection is complete and your program continues executing, the
finalizer thread then starts running in parallel to the program,
picking objects off that special queue and running their finalization
methods.
Does this paragraph mean that an object waiting for finalization need to be collected by the GC again? I assumed it already been detected as garbage by GC, why does it need to be collected after finalization again?
Well, the objects were not 'collected' the first time. They were seen to need additional processing (finalizer code needs to run) and put on the finalization queue so they could be processed separately. This ends up putting them on the 'freachable' queue, which has now resurrected the object: it is now referenced by the freachable queue and is no longer eligible for collection. It will be unreachable after the finalizer actually executes and the object is removed from the freachable queue.
(This is how it used to work, not sure if things have changed in newer .NET versions, but I'm not aware of any.)
So the object is not really 'collected' more than once, if by 'collected' we understand that the memory was reclaimed. It does, however, need additional processing and will be re-evaluated by the GC again at a later point in time.
The GC works by traversing object graphs from GC roots. When the GC does a collection it checks for objects that have no references to it (and are therefore safe to free up).
A finalizer delays garbage collection of objects.
Why? Well the GC sees that an object is safe to be free'd up (not connected to a GC root). However, it can't free the memory if there's a finalizer that hasn't run yet.
So the GC marks the object as having a pending finalizer and does not free up that space on first pass. Nor does the GC run the finalizer at that instant (it puts it in a "pending finalizer" queue).
This is exactly why it's bad practice to use finalizers unless necessary. It delays collection. Some have a misconception that the GC runs the finalizer upon a collection pass. It does not.
When is it necessary? A good rule of thumb is if the objects references unmanaged memory (which is not handled by the GC) then you absolutely should use a finalizer to avoid memory leaks. If you're only referencing managed objects then don't.
If you do implement a finalizer I would also implement IDisposable, release any unmanaged resources on Dispose and stop the finalizer ever from running with GC.SuppressFinalize(this).

Why does garbage collector process finalizable objects separately?

I am reading Jeffrey Richter's book "CLR via c#". It is quote from there:
Finalize methods are called at the completion of a garbage collection on objects that the GC
has determined to be garbage. This means that the memory for these objects cannot be reclaimed
right away because the Finalize method might execute code that accesses a field.
Because a finalizable object must survive the collection, it gets promoted to another generation, forcing the object
to live much longer than it should
It misled me a little bit. Why cannot finalizable object be reclaimed right away? I cannot understand argument that finalize method might execute code that accesses a field. What is problem? Moreover, I cannot understand why finalizable object should be moved to older generation and stored in separated queue (to be processed in other finalizer thread).
In my opinion the simplest way is to finalize object before removing at all without these additional actions.
Why cannot finalizable object be reclaimed right away? I cannot understand argument that finalize method might execute code that accesses a field. What is problem?
Because Finalize() is just a normal method of the object, so code in it might access any fields of the object.
When garbage collection happens, all threads are frozen.
The two points add up together to the fact that when gc is happening, it cannot execute the Finalize() method right away (All threads are paused during gc!!), while Finalize is expected to be invoked before object being collected.
All these above leads to the fact that garbage collection cannot kill the object immediately before its Finalize() method is invoked. So gc takes the object out from the "death list" (the object is now said to be resurrected), and put it to a queue called "Freachable" ("F" stands for finalization, "reachable" means all objects in it cannot be garbage collected now since gc only collects objects unreachable from roots).
After the gc finished, a special dedicated thread with high priority will take out each entry from the "Freachable" queue and invoke Finalize() method on it, which makes that object finally "garbage collectable", but of course, since the first gc has already ended before this Finalize() calling process, all the objects poped out from "Freachable" can now only be scheduled to next garbage collection.
Moreover, I cannot understand why finalizable object should be moved to older generation and stored in separated queue (to be processed in other finalizer thread).
To understand this, you need to first know the concept of the generation gc model. After objects are popped out from the "Freachable" queue and are again ready for garbage collection, they have been moved to older generation owing to the fact that they survive the previous one.
I think this quote says "finish your unit of work stuff and kill your instance. To kill your instance you should clean up your garbage collection because of your memory."

Access non-finalizable objects from finalizer

I want to access object without finalizer from finalizer of other instance.
I know that it is bad idea to access other finalizable object from finalizer because sequence of finalizer call is non-deterministic.
But what about accessing instances without finalizer from finalizer of other objects?
I can not figure out this, the only found in the article http://edn.embarcadero.com/article/29365 :
This means that finalizers should never access other finalizable
objects (objects without finalizers, however, are just fine)
Is any confirmation of this in MSDN?
Currently I want to acquire lock object with variable of type object but I want to be sure that it is ok and object instance is not freed from memory before accessing it.
Thanks
Currently I want to acquire lock object with variable of type object
Accessing that object in your finalizer is fine, nothing happened to it. Actually using it a lock statement, that's not so fine. Blocking the finalizer thread tends to byte badly. It has a time-out at program exit, it must complete and get everything finalized within two seconds. You cannot afford a Monitor.TryEnter() to avoid tripping that timeout, that will be a bad resource leak.
And beware the code smell, you should not be releasing whatever native resource you wrote the finalizer for when other threads can still access it. It is gospel that the finalizer can only run when nobody keeps a reference to the object anymore. Which should also mean that there shouldn't be any point in locking anymore since no thread could have a reference anymore. There is no need to protect shared state with a lock when nobody can read or write it.
Keep in mind that actually writing a finalizer tends to be almost always wrong, native resources should be finalized by their corresponding .NET wrapper class. There are many, the low-level ones are the SafeHandle derived classes.
Objects are not collected till the time they have a root. Assuming the object instance you are talking about is member of the object that is getting finalized, then that object has been alive all the time - because root is f-reachable queue.
However, I will strongly advise against any locking or blocking in finalizer. It could cause ugly deadlocks.

Why call Dispose()? Memory leak won't occur?

Edit: My question isn't getting the main answer that I was looking for. I wasn't clear. I would really like to know two things:
Can NOT calling Dispose() cause memory leaks?
What's the worst thing that can happen if you have a large program and never call Dispose() on any of your IDisposable objects?
I was under the impression that memory leaks could occur if Dispose() isn't called on IDisposable objects.
Per the discussion on this thread, my perception was incorrect; a memory leak will NOT occur if Dispose() isn't called.
Why ever bother calling Dispose() then? Is it just to free the resource immediately, instead of sometime later? What's the worst thing that can happen if you have a large program and never call Dispose() on any of your IDisposable objects?
Dispose is used to release non-managed resources. This could mean memory, if a class allocated non-managed memory, but it is more often native objects and resources like open files and database connections.
You often need to call Dispose on a class that itself doesn't have any non-managed resources, but it does contain another class that is disposable and may have non-managed resources.
It's also sometimes useful for developers to implement dispose to ensure deterministic finalization--guaranteeing the order in which resources are freed.
Also note that classes that implement dispose often also have a finalizer to release resourcdes if Dispose is not called. Objects with a finalizer have a different life-cycle than classes without one. When they are ready for GC, the GC will see that they have a finalizer and instead of immediately collecting the object when the GC is ready to, it puts it into the finalization queue. This means that the object lives for one extra GC iteration. When you call dispose, the implementation usually (but is not required to) calls GC.SuppressFinalize() which means the finalizer no longer needs to be called.
If a class implements IDisposable, you should always call Dispose().
While some other answers seem to be suggesting that you can get away with not calling it, this is really bad advice. You should always call Dispose on any IDisposable resource.
Some .NET objects have what's called a "finalizer" - something you can define on your own classes as well, but that you rarely see done in a typical C# programmer's code. The finalizer is what runs when the garbage collector destroys the object, and sometimes it will call Dispose - but only if the implementer of the class made it that way.
The best practice is to always Dispose - no matter what. There are plenty of libraries I've used where not calling Dispose on a resource results in a memory leak, a connection leak, a operating system resource leak, or other kinds of horribleness. And the garbage collector will not reconcile the problem, because they don't implement any custom finalizer.
See related: Will the Garbage Collector call IDisposable.Dispose for me?
The convention is that if an object implements IDisposable you should call Dispose() or use the "using" pattern. The difference between Dispose() and waiting for the destructor (finalizer) to execute is that Dispose() is called right away and can be used for freeing some important resources like db connections, files, devices, unmanaged oejects, etc.
So to summarize - if it is IDisposable - Dispose() it!
Not calling Dispose will not ever (*see note 2 on wrong implementation) cause traditional "memory leak" (memory is never freed till end of the process).
The "only" thing that will happen in relation to memory is it will be freed in non-deterministic moment in the future.
One interesting case of non Dispose objects is when very small managed objects hold large amounts of unmanaged memory (i.e. allocated with some flavor of Win32 memory management functions i.e. HeapAlloc ). In this case managed memory manager may not be able to detect memory pressure properly to trigger Gen2 GC and (especially in case of x86 - 32bit process) it may prematurely fail to allocate managed memory for your process. The other issue in this case is fragmentation of address space by "waiting for GC to be de-allocated" (again mostly in x86 case) - when smaller chunks of native memory are allocated with some relatively large space between them preventing allocation of large blocks needed for managed memory management.
Notes:
This answer explicitly talks about true memory leaks/memory allocation issues cased by not disposing IDisposable object managing memory. While it is true that there are no "true memory leaks" caused by such practice most people will consider growing memory usage as memory leak (similar to storing large amount of objects in static list/dictionary for lifetime of an application).
One can create object that manages native memory and incorrectly implements IDisposable pattern. In this case it is possible to really leak native memory (irrespective of calling Dispose).
In most cases objects that implement IDisposable don't managed memory at all. For most practical C# programs native resources managed by such objects are handles for system resources like files, bitmaps, fonts, synchronization objects or COM native objects. Not disposing them in timely manner will cause other issues.
Dispose all objects properly. There is no excuse not to.
Dispose() is intended to free resources that the garbage collector won't free, such as database connections. These resources should also be freed in the finalizer, however the finalizer is much slower than the Dispose() method.
For me:
Dispose can be used in using() scope. This can help me to determine the lifespan of a IDisposeable component. I usually use this in StreamWriter/Reader or SqlConnection classes.
Another use of Dispose is it can end a lifespan of a component explicitly. Such as calling Form.Dispose() in C# winform will close the form. However, for SqlConnection, people said that just calling Dispose alone without explicitly calling Close won't guarantee the connection to be closed. Advised to call both Close and Dispose. I haven't tried this though.
And another thing, after Dispose() is called, the GC can immediaetly free the memory, because they know that the object lifespan is end, rather than waiting for the lifespan to end.
Similiar question may be C# disposing IDisposable
Can NOT calling Dispose() cause memory leaks?
Yes, of course. Below is just one example.
Assume you have a main window in your application and you create a child control that has an event subscription to the main window. You unsubscribe from them on Dispose. If you don't dispose, main window can hold the reference to your child control until you close the application.
What's the worst thing that can happen if you have a large program and
never call Dispose() on any of your IDisposable objects?
The worse case is not releasing some unwanted memory until you close the application.
And the other question is, what if you never implement IDisposable or finalization when they are required?
The worse case of having a memory leak is holding on to that memory until you restart the PC. This can happen only if you have un-managed resources and you don't implement dispose/finalize. If you implement Idisposable interface and implement the finalizer, finalization process will execute the Dispose for you.
Another reason why you should call Dispose is to Suppress the finalization.
As I've indicated before if there is any object with Finalize method and you didn't call the Dispose. That object can reside in memory for two GC cycles. In the first cycle, it enqueue that instance to the finalization queue and finalization happens after GC process. So, only next GC cycle can release that memory.

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? Someone asked me this and I answered a "Yes" and then I thought: "Was that fully correct?"
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.
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();
Yes, but not straight away. This excerpt is from Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework (MSDN Magazine) (*)
"When an application creates a new object, the new operator allocates
the memory from the heap. If the object's type contains a Finalize
method, then a pointer to the object is placed on the finalization
queue. The finalization queue is an internal data structure controlled
by the garbage collector. Each entry in the queue points to an object
that should have its Finalize method called before the object's memory
can be reclaimed.
When a GC occurs ... the garbage collector scans the finalization
queue looking for pointers to these objects. When a pointer is found,
the pointer is removed from the finalization queue and appended to the
freachable queue (pronounced "F-reachable"). The freachable queue is
another internal data structure controlled by the garbage collector.
Each pointer in the freachable queue identifies an object that is
ready to have its Finalize method called.
There is a special runtime thread dedicated to calling Finalize
methods. When the freachable queue is empty (which is usually the
case), this thread sleeps. But when entries appear, this thread wakes,
removes each entry from the queue, and calls each object's Finalize
method. Because of this, you should not execute any code in a Finalize
method that makes any assumption about the thread that's executing the
code. For example, avoid accessing thread local storage in the
Finalize method."
(*) From November 2000, so things might have changed since.
When the garbage is collected (whether in response to memory pressure or GC.Collect()), the objects requiring finalization are put to finalization queue.
Unless you call GC.WaitForPendingFinalizers(), the finalizers may continue to execute in the background long after garbage collection has finished.
BTW, there is no guarantee finalizers will be called at all. From MSDN...
The Finalize method might not run to completion or might not run at
all in the following exceptional circumstances:
Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can never obtain and so on). Because the
runtime attempts to run finalizers to completion, other finalizers
might not be called if a finalizer blocks indefinitely.
The process terminates without giving the runtime a chance to clean up. In this case, the runtime's first notification of process
termination is a DLL_PROCESS_DETACH notification.
The runtime continues to Finalize objects during shutdown only while
the number of finalizable objects continues to decrease.
Couple of more points are worth to state here.
Finalizer is the last point where .net objects can release unmanaged resources.
Finalizers are to be executed only if you don’t dispose your instances correctly. Ideally, finalizers should never be executed in many cases. Because proper dispose implementation should suppress the finalization.
Here is an example for correct IDispoable Implementation.
If you call the Dispose method of any disposable objects, it should clear all references and Supress the finalization. If there is any not so good developer who forget to call the Dispose method, Finalizer is the life saver.

Categories

Resources