views:

463

answers:

6

Can I trust that an object is destroyed and its destructor is called immediately when it goes out of scope in C#?

I figure it should since many common coding practices (e.g. transaction objects) rely on this behaviour, but I'm not very used to working with garbage collection and have little insight to how such languages usually behave.

Thanks.

+13  A: 

Nope, .Net and hense C# relies on a garbage collection memory management. So destructors (which in .Net is called finalizers) are not called until GC finds it proper to destroy the objects.

Additionally: most "regular" objects in C# don't have destructors. If you need the destructor pattern you should implement the IDisposable interface with the Dispose Pattern. On disposable objects you should also make sure that the Dispose method gets called, either with the using keyword or directly calling the method.

To further (hopefully) clarify: deterministic disposal is useful in .Net e.g. when you need to explicitly free resources that is not managed by the .Net runtime. Examples of such resources are file handles, database connections, etc. It is usually important that these resources be freed as soon as they no longer are needed. Thus we cannot afford to wait for the GC to free them.

In order to get deterministic disposal (similar to the scope behavior of C++) in the non-deterministic world of the .Net GC, the .Net classes rely on the IDisposable interface. Borrowing from the Dispose Pattern, here are some examples:

First, instantiating a disposable resource and then letting the object go out of scope, will leave it up to the GC to dispose the object:

1.    {
2.       var dr = new DisposableResource();
3.    }

To fix this we can explicitly dispose the object:

1.    {
2.       var dr = new DisposableResource();
3.
4.       ...
5.
6.       dr.Dispose();
7.    }

But what if something goes wrong between line 2 and 6? Dispose will not be called. To further ensure that Dispose will finally be called regardless of any exceptions we can do the following:

1.    var dr = new DisposableResource();
2.    try
3.    {
4.       ...
5.    }
6.    finally
7.    {
8.       dr.Dispose();
9.    }

Since this pattern is often needed, C# includes the using keyword to simplify things. The following example is equivalent to the above:

1.    using (var dr = new DisposableResource())
2.    {
3.       ...
4.    }
Peter Lillevold
The question asker doesn't know the subtleties of what a C# destructor is, so I don't think you should just call a destructor a finalizer and be done with it. C++ destructors and C# destructors are *very different things.*
Joren
Also bear in mind that the .NET Garbage Collection is "generation" based, so an object can potentially be garbage collected by a Generation 0 collection, but has not been completely "destroyed" or "removed" from memory. Also think about such things as Weak References whereby an object can be garbage collected, but still accessible by your application's code! Basically, an object will last as long as the runtime wants it to. You have no say in the matter! ;) (http://www.simple-talk.com/dotnet/.net-framework/understanding-garbage-collection-in-.net/)
CraigTP
@Peter: Thanks for your response. Are you suggesting that IDisposable offers a way to achieve the scope behaviour seen in for example C++? Would you consider elaborating on it and perhaps add some code?
sharkin
Added specific link to the right way to implement IDispose.
Richard
@Richard - good thing
Peter Lillevold
Dispose does *not* provide deterministic destruction. I can't stress this enough.
Joren
@Joren - yes, I guess destruction relates to the freeing of memory. I really mean "deterministic disposal", and have rephrased thus.
Peter Lillevold
A: 

I don't think you should rely on garbage collectors in this way. Even if you deduct how they operate it might very well be that in the next release they've reimplemented it.

In any case, objects are not garbage collected the moment you unreference them. Typically they are collected until some threshold is reached and then they are released.

Especially in java programs this is very noticeable when you look at the memory consumption on the task manager. It grows and grows and all of a sudden every minute it drops again.

Toad
+3  A: 

There is no such thing als a C++-like destructor in C#. (There is a different concept of destructor in C#, also called a finalizer, which uses the same syntax as C++ destructors, but they are unrelated to destroying objects. They're intended to provide a cleanup mechanism for unmanaged resources.) The garbage collector will cleanup objects sometime after they are no longer referenced. Not immediately, and there is no way to guarantee this either.

Luckily there is also no real reason why you would want to guarantee this. If you need the memory, then the GC will reclaim it then. If you don't, why care if there's still some garbage object around? It's not a memory leak: the GC can still find it and clean it up any time.

Joren
+4  A: 

No, this isn't guaranteed. Similar to languages such as Java, in C# the garbage collector runs when it's needed (i. e. when the heap is getting too full). However, when your objects implement IDisposable, i. e. they have a Dispose() method and it has to be called, then you can take advantage of the using keyword:

using (var foo = new DisposableObject()) {
    // do something with that
}

That way Dispose() will be called immediately when leaving that using block.

Note: IDisposable is found in many types, most notably GDI+ but also database connections, transactions, etc. so it may really be the right pattern here.

Note 2: Behind the scenes above block will get translated into a try/finally block:

var foo = new DisposableObject();
try
{
    // do something with that
}
finally
{
    foo.Dispose();
}

But that translation is done by the compiler and very handy for not forgetting to call Dispose().

Joey
A: 

No. If you refer to CLI specification (p. 8.9.6.7 about Finalizers) http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf you can find the following

the CLI should ensure that finalizers are called soon after the instance becomes inaccessible. While relying on memory pressure to trigger finalization is acceptable, implementers should consider the use of additional metrics

but it must not.

Andrei Taptunov
+3  A: 

No. An object doesn't actually go "out of scope," the reference to it (i.e. the variable you use to access it) does.

Once there are no more references to a given object, that object becomes eligible for garbage collection (GC) should the need arise. Whenever the GC decides it needs to reclaim the space your no-longer-referenced object, that's when the objects finalizer will be called.

If your object is a resource (e.g. a file handle, database connection), it should implement the IDisposable interface (which obligates the object to implement a Dispose() method to clean up any open connections, etc). The best practice for you in this case would be to create the object as part of a using block, so that when this block is completed, your application will automatically call the objects Dispose() method, which will take care of closing your file/db connection/whatever.

e.g.


using (var conn = new DbConnection())  
{ 
   // do stuff with conn  
} // conn.Dispose() is automatically called here.  

The using block is just some syntactic sugar which wraps your interactions with the conn object in a try block, along with a finally block which only calls conn.Dispose()

AgentConundrum