Here is example program that exhibits surprising finalization behavior:
class Something
{
public void DoSomething()
{
Console.WriteLine("Doing something");
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
namespace TestGC
{
class Program
{
static void Main(string[] args)
{
var s = new Something();
s.DoSomething();
GC.Collect();
//GC.WaitForPendingFinalizers();
s.DoSomething();
Console.ReadKey();
}
}
}
If I run the program, what gets printed is:
Doing something
Doing something
Called finalizer
This appears as expected. Because there is a reference to s after the call to GC.Collect(), s is not a garbage.
Now remove comments from the line //GC.WaitForPendingFinalizers();
build and run the program again.
I would expect nothing to change in the output. This because I read that if object is found to be a garbage and it has a finalizer, it will be put on finalizer queue. Since object is not a garbage, then is seems logical that it should not be put on finalizer queue. Thus the line commented out should do nothing.
However, the output of the program is:
Doing something
Called finalizer
Doing something
Can somebody help my understanding of why finalizer gets called?
I can't reproduce the problem on my laptop, but your DoSomething method doesn't use any fields within the object. That means that the object can be finalized even while DoSomething is running.
If you change your code to:
class Something
{
int x = 10;
public void DoSomething()
{
x++;
Console.WriteLine("Doing something");
Console.WriteLine("x = {0}", x);
}
~Something()
{
Console.WriteLine("Called finalizer");
}
}
... then I suspect you will always see DoingSomething printed twice before "Called finalizer" - although the final "x = 12" may be printed after "Called finalizer".
Basically, finalization can be somewhat surprising - I very rarely find myself using it, and would encourage you to avoid finalizers wherever possible.
Jon's answer is of course correct. I would add to it that the C# specification calls out that the compiler and runtime are allowed to (but not required to) notice that the reference contained in a local variable is never again dereferenced, and at that point the garbage collector is allowed to treat the object as dead if the local is the last living reference. Therefore the object can be collected and the finalizer run even though there appears to be a reference in a living local variable. (And similarly the compiler and runtime are allowed to make locals live longer if they so choose.)
Given this fact you can end up in bizarre situations. For example, it is possible for a finalizer to be executing on the finalizer thread while the object's constructor is running on a user thread. If the runtime can determine that "this" is never dereferenced again then the object can be treated as dead the moment the constructor is done mutating fields of "this". If the constructor then does additional work -- say, mutating global state -- then that work can be done as the finalizer is running.
This is just yet another reason why writing a correct finalizer is so difficult that you probably should not do so. In a finalizer everything you know is wrong. Everything you're referring to could be dead, you're on a different thread, the object might not be fully constructed, possibly none of your program invariants are actually maintained.
Your DoSomething() is so trivial that it's likely to get inlined. After it's been inlined, there's nothing that still has a reference to the object, so there's nothing preventing it from being garbage collected.
GC.KeepAlive() is designed specifically for this scenario. It can be used if you want to prevent an object from being garbage collected. It does nothing, but the garbage collector doesn't know that. Call GC.KeepAlive(s); at the end of Main to prevent it from being finalised earlier.
Related
(I don't even know whether my question makes sense at all; it is just something that I do not understand and is spinning in my head for some time)
Consider having the following class:
public class MyClass
{
private int _myVar;
public void DoSomething()
{
// ...Do something...
_myVar = 1;
System.Console.WriteLine("Inside");
}
}
And using this class like this:
public class Test
{
public static void Main()
{
// ...Some code...
System.Console.WriteLine("Before");
// No assignment to a variable.
new MyClass().DoSomething();
// ...Some other code...
System.Console.WriteLine("After");
}
}
(Ideone)
Above, I'm creating an instance of a class without assigning it to a variable.
I fear that the garbage collector could delete my instance too early.
My naive understanding of garbage collection is:
"Delete an object as soon as no references point to it."
Since I create my instance without assigning it to a variable, this condition would be true. Obviously the code runs correct, so my asumption seems to be false.
Can someone give me the information I am missing?
To summarize, my question is:
(Why/why not) is it safe to instantiate a class without asigning it to a variable or returning it?
I.e. is
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
the same from a garbage collection point-of-view?
It's somewhat safe. Or rather, it's as safe as if you had a variable which isn't used after the method call anyway.
An object is eligible for garbage collection (which isn't the same as saying it will be garbage collected immediately) when the GC can prove that nothing is going to use any of its data any more.
This can occur even while an instance method is executing if the method isn't going to use any fields from the current execution point onwards. This can be quite surprising, but isn't normally an issue unless you have a finalizer, which is vanishingly rare these days.
When you're using the debugger, the garbage collector is much more conservative about what it will collect, by the way.
Here's a demo of this "early collection" - well, early finalization in this case, as that's easier to demonstrate, but I think it proves the point clearly enough:
using System;
using System.Threading;
class EarlyFinalizationDemo
{
int x = Environment.TickCount;
~EarlyFinalizationDemo()
{
Test.Log("Finalizer called");
}
public void SomeMethod()
{
Test.Log("Entered SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Collected once");
Test.Log("Value of x: " + x);
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Exiting SomeMethod");
}
}
class Test
{
static void Main()
{
var demo = new EarlyFinalizationDemo();
demo.SomeMethod();
Test.Log("SomeMethod finished");
Thread.Sleep(1000);
Test.Log("Main finished");
}
public static void Log(string message)
{
// Ensure all log entries are spaced out
lock (typeof(Test))
{
Console.WriteLine("{0:HH:mm:ss.FFF}: {1}",
DateTime.Now, message);
Thread.Sleep(50);
}
}
}
Output:
10:09:24.457: Entered SomeMethod
10:09:25.511: Collected once
10:09:25.562: Value of x: 73479281
10:09:25.616: Finalizer called
10:09:26.666: Exiting SomeMethod
10:09:26.717: SomeMethod finished
10:09:27.769: Main finished
Note how the object is finalized after the value of x has been printed (as we need the object in order to retrieve x) but before SomeMethod completes.
The other answers are all good but I want to emphasize a few points here.
The question essentially boils down to: when is the garbage collector allowed to deduce that a given object is dead? and the answer is the garbage collector has broad latitude to use any technique it chooses to determine when an object is dead, and this broad latitude can lead to some surprising results.
So let's start with:
My naive understanding of garbage collection is: "Delete an object as soon as no references point to it."
This understanding is wrong wrong wrong. Suppose we have
class C { C c; public C() { this.c = this; } }
Now every instance of C has a reference to it stored inside itself. If objects were only reclaimed when the reference count to them was zero then circularly referenced objects would never be cleaned up.
A correct understanding is:
Certain references are "known roots". When a collection happens the known roots are traced. That is, all known roots are alive, and everything that something alive refers to is also alive, transitively. Everything else is dead, and eligable for reclamation.
Dead objects that require finalization are not collected. Rather, they are kept alive on the finalization queue, which is a known root, until their finalizers run, after which they are marked as no longer requiring finalization. A future collection will identify them as dead a second time and they will be reclaimed.
Lots of things are known roots. Static fields, for example, are all known roots. Local variables might be known roots, but as we'll see below, they can be optimized away in surprising ways. Temporary values might be known roots.
I'm creating an instance of a class without assigning it to a variable.
Your question here is a good one but it is based on an incorrect assumption, namely that a local variable is always a known root. Assigning a reference to a local variable does not necessarily keep an object alive. The garbage collector is allowed to optimize away local variables at its whim.
Let's give an example:
void M()
{
var resource = OpenAFile();
int handle = resource.GetHandle();
UnmanagedCode.MessWithFile(handle);
}
Suppose resource is an instance of a class that has a finalizer, and the finalizer closes the file. Can the finalizer run before MessWithFile? Yes! The fact that resource is a local variable with a lifetime of the entire body of M is irrelevant. The runtime can realize that this code could be optimized into:
void M()
{
int handle;
{
var resource = OpenAFile();
handle = resource.GetHandle();
}
UnmanagedCode.MessWithFile(handle);
}
and now resource is dead by the time MessWithFile is called. It is unlikely but legal for the finalizer to run between GetHandle and MessWithFile, and now we're messing with a file that has been closed.
The correct solution here is to use GC.KeepAlive on the resource after the call to MessWithFile.
To return to your question, your concern is basically "is the temporary location of a reference a known root?" and the answer is usually yes, with the caveat that again, if the runtime can determine that a reference is never dereferenced then it is allowed to tell the GC that the referenced object might be dead.
Put another way: you asked if
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
are the same from the point of view of the GC. Yes. In both cases the GC is allowed to kill the object the moment that it determines it can do so safely, regardless of the lifetime of local variable c.
The shorter answer to your question is: trust the garbage collector. It has been carefully written to do the right thing. The only times you need to worry about the GC doing the wrong thing are scenarios like the one I laid out, where timing of finalizers is important for the correctness of unmanaged code calls.
Of course, GC is transparent to you and no early collection can ever happen. So I guess you want to know the implementation details:
An instance method is implemented like a static method with an additional this parameter. In your case the this value lives in registers and is passed like that into DoSomething. The GC is aware what registers contain live references and will treat them as roots.
As long as DoSomething might still use the this value it stays live. If DoSomething never uses instance state then indeed the instance can be collected while a method call is still running on it. This is unobservable, therefore safe.
As long as you're talking about a single threaded environment, you're safe. Fun things only start to happen if you're starting a new thread inside the DoSomething method, and even more fun happens if your class has a finalizer. The key thing to understand here is that a lot of the contracts between you and the runtime / optimizer / etc. are valid only in a single thread. This is one of the things that has disastrous results when you start programming on multiple threads in a language that isn't primaririly multi-threading oriented (yes, C# is one of those languages).
In your case, you're even using the this instance, which makes unexpected collection even less likely while still inside that method; in any case, the contract is that on a single thread, you can't observe the difference between the optimized and unoptimized code (apart from memory usage, speed, etc., but those are the "free lunch").
I have a class:
public class SomeClass {
public int I;
public SomeClass(int input) {
I = input;
Console.WriteLine("I = {0}", I);
}
~SomeClass() {
Console.WriteLine("deleted");
}
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
}
and this program:
class Program {
static void Main(string[] args) {
new Thread(() => {
Thread.Sleep(100);
GC.Collect();
}) { IsBackground = true }.Start();
new SomeClass(10).Foo();
// The same as upper code
// var t = new SomeClass(10);
// t.Foo();
}
}
When i run this code in Debug mode, i have next result:
I = 10
Foo
deleted
but, when i change mode to Release, result changes to:
I = 10
deleted
Foo
As i understand, there is difference with call and callvirt: when optimization starts in Release mode, compiler look at Foo method and can't find any reference to SomeClass in this method, and that's why this method calls as static method by address, and garbage collector could collect this object.
Otherwise, if i change Foo method (for example, add Console.WriteLine(I) into this method), compiler won't decide to call this method as call and it should be called by pointer to instance with callvirt and garbage collector won't collect this object.
Can you please explain more clearly, what's going on here (why GC could collect object and if it's so, how does method calls).
I doubt that it's really anything to do with call and callvirt.
I strongly suspect it's simply because you're not using any fields within SomeClass.Foo. The garbage collector is free to collect an object when it is certain that none of the data will be referenced again - so no code is going to look at any references to the object, or any fields within the object.
Basically, if you write a finalizer and you need to ensure that the object isn't finalized while methods within that object are running, you need to be very careful. You can use GC.KeepAlive(this) at the end of methods, as one approach, but it's a bit ugly. I would personally try very hard to avoid needing a finalizer at all, if you can. I can't remember the last time I wrote one. (See Joe Duffy's blog for more.)
When there's a debugger attached, the GC is much less aggressive about what it can collect - after all, if you can break into the debugger at any point and inspect the fields of any object that is the target of a running instance method, that removes the possibility of garbage collecting those objects.
When you're debugging, the whole system1 extends the lifetime of objects beyond their natural lifetime.
So, when a thread is executing this method:
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
This method makes no use of this. So when not debugging, after this method has started running, it doesn't require the object to exist any longer.
However, when debugging, you might have set a breakpoint on that Console.WrtieLine method, and from there decide to inspect this. So the system conspires to keep this alive (as well as any local variables which are no longer used within the body of a method).
1This old presentation shows how the JIT and GC actually work together to work out which references are live (see slide 30 onwards). It is my understanding that the JIT does more work to help out with debugging - by not reusing local variable slots which it could (so values are still visible) and by informing the GC that all variables are alive throughout the method, rather than the more piecemeal analysis it can provide.
I have a timer in C# which executes some code inside it's method. Inside the code I'm using several temporary objects.
If I have something like Foo o = new Foo(); inside the method, does that mean that each time the timer ticks, I'm creating a new object and a new reference to that object?
If I have string foo = null and then I just put something temporal in foo, is it the same as above?
Does the garbage collector ever delete the object and the reference or objects are continually created and stay in memory?
If I just declare Foo o; and not point it to any instance, isn't that disposed when the method ends?
If I want to ensure that everything is deleted, what is the best way of doing it:
with the using statement inside the method
by calling dispose method at the end
by putting Foo o; outside the timer's method and just make the assignment o = new Foo() inside, so then the pointer to the object is deleted after the method ends, the garbage collector will delete the object.
1.If I have something like Foo o = new Foo(); inside the method, does that
mean that each time the timer ticks,
I'm creating a new object and a new
reference to that object?
Yes.
2.If I have string foo = null and then I just put something temporal in foo,
is it the same as above?
If you are asking if the behavior is the same then yes.
3.Does the garbage collector ever delete the object and the reference or
objects are continually created and
stay in memory?
The memory used by those objects is most certainly collected after the references are deemed to be unused.
4.If I just declare Foo o; and not point it to any instance, isn't that
disposed when the method ends?
No, since no object was created then there is no object to collect (dispose is not the right word).
5.If I want to ensure that everything is deleted, what is the best way of
doing it
If the object's class implements IDisposable then you certainly want to greedily call Dispose as soon as possible. The using keyword makes this easier because it calls Dispose automatically in an exception-safe way.
Other than that there really is nothing else you need to do except to stop using the object. If the reference is a local variable then when it goes out of scope it will be eligible for collection.1 If it is a class level variable then you may need to assign null to it to make it eligible before the containing class is eligible.
1This is technically incorrect (or at least a little misleading). An object can be eligible for collection long before it goes out of scope. The CLR is optimized to collect memory when it detects that a reference is no longer used. In extreme cases the CLR can collect an object even while one of its methods is still executing!
Update:
Here is an example that demonstrates that the GC will collect objects even though they may still be in-scope. You have to compile a Release build and run this outside of the debugger.
static void Main(string[] args)
{
Console.WriteLine("Before allocation");
var bo = new BigObject();
Console.WriteLine("After allocation");
bo.SomeMethod();
Console.ReadLine();
// The object is technically in-scope here which means it must still be rooted.
}
private class BigObject
{
private byte[] LotsOfMemory = new byte[Int32.MaxValue / 4];
public BigObject()
{
Console.WriteLine("BigObject()");
}
~BigObject()
{
Console.WriteLine("~BigObject()");
}
public void SomeMethod()
{
Console.WriteLine("Begin SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("End SomeMethod");
}
}
On my machine the finalizer is run while SomeMethod is still executing!
The .NET garbage collector takes care of all this for you.
It is able to determine when objects are no longer referenced and will (eventually) free the memory that had been allocated to them.
Objects are eligable for garbage collection once they go out of scope become unreachable (thanks ben!). The memory won't be freed unless the garbage collector believes you are running out of memory.
For managed resources, the garbage collector will know when this is, and you don't need to do anything.
For unmanaged resources (such as connections to databases or opened files) the garbage collector has no way of knowing how much memory they are consuming, and that is why you need to free them manually (using dispose, or much better still the using block)
If objects are not being freed, either you have plenty of memory left and there is no need, or you are maintaining a reference to them in your application, and therefore the garbage collector will not free them (in case you actually use this reference you maintained)
Let's answer your questions one by one.
Yes, you make a new object whenever this statement is executed, however, it goes "out of scope" when you exit the method and it is eligible for garbage collection.
Well this would be the same as #1, except that you've used a string type. A string type is immutable and you get a new object every time you make an assignment.
Yes the garbage collector collects the out of scope objects, unless you assign the object to a variable with a large scope such as class variable.
Yes.
The using statement only applies to objects that implement the IDisposable interface. If that is the case, by all means using is best for objects within a method's scope. Don't put Foo o at a larger scope unless you have a good reason to do so. It is best to limit the scope of any variable to the smallest scope that makes sense.
Here's a quick overview:
Once references are gone, your object will likely be garbage collected.
You can only count on statistical collection that keeps your heap size normal provided all references to garbage are really gone. In other words, there is no guarantee a specific object will ever be garbage collected.
It follows that your finalizer will also never be guaranteed to be called. Avoid finalizers.
Two common sources of leaks:
Event handlers and delegates are references. If you subscribe to an event of an object, you are referencing to it. If you have a delegate to an object's method, you are referencing it.
Unmanaged resources, by definition, are not automatically collected. This is what the IDisposable pattern is for.
Finally, if you want a reference that does not prevent the object from getting collected, look into WeakReference.
One last thing: If you declare Foo foo; without assigning it you don't have to worry - nothing is leaked. If Foo is a reference type, nothing was created. If Foo is a value type, it is allocated on the stack and thus will automatically be cleaned up.
Yes
What do you mean by the same? It will be re-executed every time the method is run.
Yes, the .Net garbage collector uses an algorithm that starts with any global/in-scope variables, traverses them while following any reference it finds recursively, and deletes any object in memory deemed to be unreachable. see here for more detail on Garbage Collection
Yes, the memory from all variables declared in a method is released when the method exits as they are all unreachable. In addition, any variables that are declared but never used will be optimized out by the compiler, so in reality your Foo variable will never ever take up memory.
the using statement simply calls dispose on an IDisposable object when it exits, so this is equivalent to your second bullet point. Both will indicate that you are done with the object and tell the GC that you are ready to let go of it. Overwriting the only reference to the object will have a similar effect.
The garbage collector will come around and clean up anything that no longer has references to it. Unless you have unmanaged resources inside Foo, calling Dispose or using a using statement on it won't really help you much.
I'm fairly sure this applies, since it was still in C#. But, I took a game design course using XNA and we spent some time talking about the garbage collector for C#. Garbage collecting is expensive, since you have to check if you have any references to the object you want to collect. So, the GC tries to put this off as long as possible. So, as long as you weren't running out of physical memory when your program went to 700MB, it might just be the GC being lazy and not worrying about it yet.
But, if you just use Foo o outside the loop and create a o = new Foo() each time around, it should all work out fine.
As Brian points out the GC can collect anything that is unreachable including objects that are still in scope and even while instance methods of those objects are still executing. consider the following code:
class foo
{
static int liveFooInstances;
public foo()
{
Interlocked.Increment(ref foo.liveFooInstances);
}
public void TestMethod()
{
Console.WriteLine("entering method");
while (Interlocked.CompareExchange(ref foo.liveFooInstances, 1, 1) == 1)
{
Console.WriteLine("running GC.Collect");
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("exiting method");
}
~foo()
{
Console.WriteLine("in ~foo");
Interlocked.Decrement(ref foo.liveFooInstances);
}
}
class Program
{
static void Main(string[] args)
{
foo aFoo = new foo();
aFoo.TestMethod();
//Console.WriteLine(aFoo.ToString()); // if this line is uncommented TestMethod will never return
}
}
if run with a debug build, with the debugger attached, or with the specified line uncommented TestMethod will never return. But running without a debugger attached TestMethod will return.
I have an application with two classes, A and B. The class A has inside a reference to class B. The destructors of the classes do some cleanup of resources but they have to be called in the right order, first the destructor of A and then the destructor of B.
What is happening is that somehow the destructor of B is called first and then the destructor of A is crashing because is trying to execute methods from a disposed object.
Is this behavior of the GC correct? I expected the GC to detect that A has a reference to B and then call the A destructor first. Am I right?
Thanks mates!
PD: In case of doubt about destructor/finalizer/disposer etc that's what we have:
~A()
{
this.Dispose();
}
~B()
{
this.Dispose();
}
As others have noted, your finalizers are wrong, wrong, wrong. You cannot simply call Dispose in a finalizer and expect good things to happen. Read up on the correct way to implement the disposable pattern.
Getting that right is the beginning, not the end, of the work you have to do. In addition to all the other correct answers here, I note that:
the finalizer can (and usually does) run on a different thread. Finalizing resources that have an affinity to a particular thread is dangerous, you can run into deadlocks if you are not careful, and so on.
finalization can "resurrect" a dead object by assigning a reference to it to a variable that is in a live object. Do not do that. It is incredibly confusing.
finalizers can run on objects that were partially constructed when a thread abort exception happened. You cannot assume that any invariant that is true of a fully-constructed object is true of an object being finalized.
Writing a finalizer correctly is extremely difficult for all these reasons. Avoid, avoid, avoid.
The GC is nondeterministic: it is not guaranteed to garbage-collect your objects in any particular order, or at any time, or even ever---it could decide to keep them around after your program is completed, if it wanted to. Thus finalizers are very rarely useful or used.
If you want deterministic finalization, you should use the IDisposable pattern.
From http://msdn.microsoft.com/en-us/magazine/bb985010.aspx:
The runtime doesn't make any guarantees as to the order in which Finalize methods are called. For example, let's say there is an object that contains a pointer to an inner object. The garbage collector has detected that both objects are garbage. Furthermore, say that the inner object's Finalize method gets called first. Now, the outer object's Finalize method is allowed to access the inner object and call methods on it, but the inner object has been finalized and the results may be unpredictable. For this reason, it is strongly recommended that Finalize methods not access any inner, member objects.
You should not write code that depends on the deconstructors in C#, they might never be run so can not be depended upon.
The correct way to write finalizers is to not call anything on related objects, you should only destroy unmanaged resources through the finalizer, precisely because, as you've noted, things happen out of order.
As others have noted, this is documented as part of the specification, so this is not a bug, nor is it something that will change to "do the right thing". In particular, think about two objects both having a reference to the other, it would be impossible for the runtime to figure out what the correct order would be here.
In any case, here's how you should implement a finalizer. Note that you should only implement a finalizer if you need to destroy unmanaged resources (note, there are some edge-cases where you might want a finalizer for a very special-purpose class, but I won't mention these here any more than this):
public class Test : IDisposable
{
~Test()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
// TODO: Make sure calling Dispose twice is safe
if (disposing)
{
// call Dispose method on other objects
GC.SuppressFinalize(this);
}
// destroy unmanaged resources here
}
}
You can find more information here: Implementing a Dispose Method.
I ran the following code and found that finalizer is always called. But many articles said that finalizer is non-desterministic.
class Test
{
Test()
{
throw new Exception();
}
~Test()
{
Console.WriteLine("Finalizer is called");
}
static void Main()
{
try
{
new Test();
}
catch { }
}
It is still non-deterministic in your case. Non-deterministic means the amount of time it takes for something to happen cannot be pre-calculated. Note that being unable to correctly determine when something will happen does not necessarily mean random-time but in most cases they are roughly the same.
People who never have to control car brakes, industrial robots or the space shuttle generally should not care weather a piece of code is deterministic or not.
note: I have written code to control industrial robots so I sometimes need to care about my code being executed at the exact moment I want it to be.
The garbage collector calls the finalizer when it collects the object. You can suppress the finalizer call by calling GC.SuppressFinalize(); Documentation
You could place this call inside Dispose() to stop the garbage collector from collecting the class after its resources have been disposed.
In your case, the finalizer is running as part of application shutdown. From the docs:
During shutdown of an application
domain, Finalize is automatically
called on objects that are not exempt
from finalization, even those that are
still accessible.
Non-deterministic refers to when Finalize will be called. But except in exceptional cases (like power being cut off or the process being abruptly killed), the finalizer will eventually be called.
There are cases when it may not be called; and cases where even if it is called, it may not be allowed to complete.
While there are certain occasions when the finalizer will not be called, it will typically be called. The big issue is when it is called, hence it is non-deterministic.
C# is garbage-collected and the garbage collector runs at unspecified intervals. Therefore, if the finalizer needs to do something time-sensitive, it is best to use Dispose instead of a finalizer. For example, you might want to close a database connection immediately instead of leaving it open while waiting for the garbage collector.
That code is so simple that the .NET Runtime can run the finalizer with out problems but in high load applications the Finalizers are only called when garbage collection runs.
There is here an extract of this article
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
Finalization
The garbage collector offers an additional feature that you may want to take advantage of: finalization. Finalization allows a resource to gracefully clean up after itself when it is being collected. By using finalization, a resource representing a file or network connection is able to clean itself up properly when the garbage collector decides to free the resource's memory.
Here is an oversimplification of what happens: when the garbage collector detects that an object is garbage, the garbage collector calls the object's Finalize method (if it exists) and then the object's memory is reclaimed. For example, let's say you have the following type (in C#):
public class BaseObj {
BaseObj() {}
protected override void Finalize() {
// Perform resource cleanup code here...
// Example: Close file/Close network connection
Console.WriteLine("In Finalize.");
}
}
Now you can create an instance of this object by calling:
BaseObj bo = new BaseObj();
Some time in the future, the garbage collector will determine that this object is garbage. When that happens, the garbage collector will see that the type has a Finalize method and will call the method, causing "In Finalize" to appear in the console window and reclaiming the memory block used by this object.