Do you need to dispose of objects and set them to null, or will the garbage collector clean them up when they go out of scope?
Objects will be cleaned up when they are no longer being used and when the garbage collector sees fit. Sometimes, you may need to set an object to null in order to make it go out of scope (such as a static field whose value you no longer need), but overall there is usually no need to set to null.
Regarding disposing objects, I agree with #Andre. If the object is IDisposable it is a good idea to dispose it when you no longer need it, especially if the object uses unmanaged resources. Not disposing unmanaged resources will lead to memory leaks.
You can use the using statement to automatically dispose an object once your program leaves the scope of the using statement.
using (MyIDisposableObject obj = new MyIDisposableObject())
{
// use the object here
} // the object is disposed here
Which is functionally equivalent to:
MyIDisposableObject obj;
try
{
obj = new MyIDisposableObject();
}
finally
{
if (obj != null)
{
((IDisposable)obj).Dispose();
}
}
Objects never go out of scope in C# as they do in C++. They are dealt with by the Garbage Collector automatically when they are not used anymore. This is a more complicated approach than C++ where the scope of a variable is entirely deterministic. CLR garbage collector actively goes through all objects that have been created and works out if they are being used.
An object can go "out of scope" in one function but if its value is returned, then GC would look at whether or not the calling function holds onto the return value.
Setting object references to null is unnecessary as garbage collection works by working out which objects are being referenced by other objects.
In practice, you don't have to worry about destruction, it just works and it's great :)
Dispose must be called on all objects that implement IDisposable when you are finished working with them. Normally you would use a using block with those objects like so:
using (var ms = new MemoryStream()) {
//...
}
EDIT On variable scope. Craig has asked whether the variable scope has any effect on the object lifetime. To properly explain that aspect of CLR, I'll need to explain a few concepts from C++ and C#.
Actual variable scope
In both languages the variable can only be used in the same scope as it was defined - class, function or a statement block enclosed by braces. The subtle difference, however, is that in C#, variables cannot be redefined in a nested block.
In C++, this is perfectly legal:
int iVal = 8;
//iVal == 8
if (iVal == 8){
int iVal = 5;
//iVal == 5
}
//iVal == 8
In C#, however you get a a compiler error:
int iVal = 8;
if(iVal == 8) {
int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}
This makes sense if you look at generated MSIL - all the variables used by the function are defined at the start of the function. Take a look at this function:
public static void Scope() {
int iVal = 8;
if(iVal == 8) {
int iVal2 = 5;
}
}
Below is the generated IL. Note that iVal2, which is defined inside the if block is actually defined at function level. Effectively this means that C# only has class and function level scope as far as variable lifetime is concerned.
.method public hidebysig static void Scope() cil managed
{
// Code size 19 (0x13)
.maxstack 2
.locals init ([0] int32 iVal,
[1] int32 iVal2,
[2] bool CS$4$0000)
//Function IL - omitted
} // end of method Test2::Scope
C++ scope and object lifetime
Whenever a C++ variable, allocated on the stack, goes out of scope it gets destructed. Remember that in C++ you can create objects on the stack or on the heap. When you create them on the stack, once execution leaves the scope, they get popped off the stack and gets destroyed.
if (true) {
MyClass stackObj; //created on the stack
MyClass heapObj = new MyClass(); //created on the heap
obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives
When C++ objects are created on the heap, they must be explicitly destroyed, otherwise it is a memory leak. No such problem with stack variables though.
C# Object Lifetime
In CLR, objects (i.e. reference types) are always created on the managed heap. This is further reinforced by object creation syntax. Consider this code snippet.
MyClass stackObj;
In C++ this would create an instance on MyClass on the stack and call its default constructor. In C# it would create a reference to class MyClass that doesn't point to anything. The only way to create an instance of a class is by using new operator:
MyClass stackObj = new MyClass();
In a way, C# objects are a lot like objects that are created using new syntax in C++ - they are created on the heap but unlike C++ objects, they are managed by the runtime, so you don't have to worry about destructing them.
Since the objects are always on the heap the fact that object references (i.e. pointers) go out of scope becomes moot. There are more factors involved in determining if an object is to be collected than simply presence of references to the object.
C# Object references
Jon Skeet compared object references in Java to pieces of string that are attached to the balloon, which is the object. Same analogy applies to C# object references. They simply point to a location of the heap that contains the object. Thus, setting it to null has no immediate effect on the object lifetime, the balloon continues to exist, until the GC "pops" it.
Continuing down the balloon analogy, it would seem logical that once the balloon has no strings attached to it, it can be destroyed. In fact this is exactly how reference counted objects work in non-managed languages. Except this approach doesn't work for circular references very well. Imagine two balloons that are attached together by a string but neither balloon has a string to anything else. Under simple ref counting rules, they both continue to exist, even though the whole balloon group is "orphaned".
.NET objects are a lot like helium balloons under a roof. When the roof opens (GC runs) - the unused balloons float away, even though there might be groups of balloons that are tethered together.
.NET GC uses a combination of generational GC and mark and sweep. Generational approach involves the runtime favouring to inspect objects that have been allocated most recently, as they are more likely to be unused and mark and sweep involves runtime going through the whole object graph and working out if there are object groups that are unused. This adequately deals with circular dependency problem.
Also, .NET GC runs on another thread(so called finalizer thread) as it has quite a bit to do and doing that on the main thread would interrupt your program.
As others have said you definitely want to call Dispose if the class implements IDisposable. I take a fairly rigid position on this. Some might claim that calling Dispose on DataSet, for example, is pointless because they disassembled it and saw that it did not do anything meaningful. But, I think there are fallacies abound in that argument.
Read this for an interesting debate by respected individuals on the subject. Then read my reasoning here why I think Jeffery Richter is in the wrong camp.
Now, on to whether or not you should set a reference to null. The answer is no. Let me illustrate my point with the following code.
public static void Main()
{
Object a = new Object();
Console.WriteLine("object created");
DoSomething(a);
Console.WriteLine("object used");
a = null;
Console.WriteLine("reference set to null");
}
So when do you think the object referenced by a is eligible for collection? If you said after the call to a = null then you are wrong. If you said after the Main method completes then you are also wrong. The correct answer is that it is eligible for collection sometime during the call to DoSomething. That is right. It is eligible before the reference is set to null and perhaps even before the call to DoSomething completes. That is because the JIT compiler can recognize when object references are no longer dereferenced even if they are still rooted.
You never need to set objects to null in C#. The compiler and runtime will take care of figuring out when they are no longer in scope.
Yes, you should dispose of objects that implement IDisposable.
If the object implements IDisposable, then yes, you should dispose it. The object could be hanging on to native resources (file handles, OS objects) that might not be freed immediately otherwise. This can lead to resource starvation, file-locking issues, and other subtle bugs that could otherwise be avoided.
See also Implementing a Dispose Method on MSDN.
I agree with the common answer here that yes you should dispose and no you generally shouldn't set the variable to null... but I wanted to point out that dispose is NOT primarily about memory management. Yes, it can help (and sometimes does) with memory management, but it's primary purpose is to give you deterministic releasing of scarce resources.
For example, if you open a hardware port (serial for example), a TCP/IP socket, a file (in exclusive access mode) or even a database connection you have now prevented any other code from using those items until they are released. Dispose generally releases these items (along with GDI and other "os" handles etc. which there are 1000's of available, but are still limited overall). If you don't call dipose on the owner object and explicitly release these resources, then try to open the same resource again in the future (or another program does) that open attempt will fail because your undisposed, uncollected object still has the item open. Of course, when the GC collects the item (if the Dispose pattern has been implemented correctly) the resource will get released... but you don't know when that will be, so you don't know when it's safe to re-open that resource. This is the primary issue Dispose works around. Of course, releasing these handles often releases memory too, and never releasing them may never release that memory... hence all the talk about memory leaks, or delays in memory clean up.
I have seen real world examples of this causing problems. For instance, I have seen ASP.Net web applications that eventually fail to connect to the database (albeit for short periods of time, or until the web server process is restarted) because the sql server 'connection pool is full'... i.e, so many connections have been created and not explicitly released in so short a period of time that no new connections can be created and many of the connections in the pool, although not active, are still referenced by undiposed and uncollected objects and so can't be reused. Correctly disposing the database connections where necessary ensures this problem doesn't happen (at least not unless you have very high concurrent access).
If they implement the IDisposable interface then you should dispose them. The garbage collector will take care of the rest.
EDIT: best is to use the using command when working with disposable items:
using(var con = new SqlConnection("..")){ ...
Always call dispose. It is not worth the risk. Big managed enterprise applications should be treated with respect. No assumptions can be made or else it will come back to bite you.
Don't listen to leppie.
A lot of objects don't actually implement IDisposable, so you don't have to worry about them. If they genuinely go out of scope they will be freed automatically. Also I have never come across the situation where I have had to set something to null.
One thing that can happen is that a lot of objects can be held open. This can greatly increase the memory usage of your application. Sometimes it is hard to work out whether this is actually a memory leak, or whether your application is just doing a lot of stuff.
Memory profile tools can help with things like that, but it can be tricky.
In addition always unsubscribe from events that are not needed. Also be careful with WPF binding and controls. Not a usual situation, but I came across a situation where I had a WPF control that was being bound to an underlying object. The underlying object was large and took up a large amount of memory. The WPF control was being replaced with a new instance, and the old one was still hanging around for some reason. This caused a large memory leak.
In hindsite the code was poorly written, but the point is that you want to make sure that things that are not used go out of scope. That one took a long time to find with a memory profiler as it is hard to know what stuff in memory is valid, and what shouldn't be there.
When an object implements IDisposable you should call Dispose (or Close, in some cases, that will call Dispose for you).
You normally do not have to set objects to null, because the GC will know that an object will not be used anymore.
There is one exception when I set objects to null. When I retrieve a lot of objects (from the database) that I need to work on, and store them in a collection (or array). When the "work" is done, I set the object to null, because the GC does not know I'm finished working with it.
Example:
using (var db = GetDatabase()) {
// Retrieves array of keys
var keys = db.GetRecords(mySelection);
for(int i = 0; i < keys.Length; i++) {
var record = db.GetRecord(keys[i]);
record.DoWork();
keys[i] = null; // GC can dispose of key now
// The record had gone out of scope automatically,
// and does not need any special treatment
}
} // end using => db.Dispose is called
Normally, there's no need to set fields to null. I'd always recommend disposing unmanaged resources however.
From experience I'd also advise you to do the following:
Unsubscribe from events if you no longer need them.
Set any field holding a delegate or an expression to null if it's no longer needed.
I've come across some very hard to find issues that were the direct result of not following the advice above.
A good place to do this is in Dispose(), but sooner is usually better.
In general, if a reference exists to an object the garbage collector (GC) may take a couple of generations longer to figure out that an object is no longer in use. All the while the object remains in memory.
That may not be a problem until you find that your app is using a lot more memory than you'd expect. When that happens, hook up a memory profiler to see what objects are not being cleaned up. Setting fields referencing other objects to null and clearing collections on disposal can really help the GC figure out what objects it can remove from memory. The GC will reclaim the used memory faster making your app a lot less memory hungry and faster.
I have to answer, too.
The JIT generates tables together with the code from it's static analysis of variable usage.
Those table entries are the "GC-Roots" in the current stack frame. As the instruction pointer advances, those table entries become invalid and so ready for garbage collection.
Therefore: If it is a scoped variable, you don't need to set it to null - the GC will collect the object.
If it is a member or a static variable, you have to set it to null
A little late to the party, but there is one scenario that I don't think has been mentioned here - if class A implements IDisposable, and exposes public properties that are also IDisposable objects, then I think it's good practice for class A not only to dispose of the disposable objects that it has created in its Dispose method, but also to set them to null. The reason for this is that disposing an object and letting it get GCed (because there are no more references to it) are by no means the same thing, although it is pretty definitely a bug if it happens. If a client of Class A does dispose its object of type ClassA, the object still exists. If the client then tries to access one of these public properties (which have also now been disposed) the results can be quite unexpected. If they have been nulled as well as disposed, there will be a null reference exception immediately, which will make the problem easier to diagnose.
Related
NET for a long time now and have started to learn C#. One thing I suppose I may have asked years ago, got the answer but have completely forgotten it now as it is not something I implicitly use a lot is destructors. As I am going through learning C# I read an article about how to create these in C# however it has left me wondering. Let say I instantiate a class which has an object to another class.
Class C1
{
// Do something here
}
Class A
{
C1 objObjectToClass1 = new C1();
}
Class Main
{
A objObjectToClassA = new A();
}
and I make the object objObjectToClassA to null as I have been lead to believe that is the equivalent to object = nothing in VB.NET.
objObectToClassA = null;
Does this action also destroy objObjectToClass1?
Not as such, no. An object will be reclaimed by the garbage collector some time after it has become eligible for collection. This may be after you clear the last reference to it, but it could already be before if you never need the reference anymore after a certain point. But generally, setting a field where you store the instance to null will help the object becoming no longer reachable and getting reclaimed.
Generally you have no control over when objects are reclaimed by the GC. You can write finalizers which are methods that are called prior to reclaiming an object, but I'd very much not recommend it if you can help it. If you need a predictable way of causing an object to release any resources it might hold on to (what destructors in C++ often do), then implement the IDisposable interface:
class C1 : IDisposable {
public void Dispose() {
// Do cleanup here
}
}
This also enables you to use instances of that class in a using statement, which will call Dispose at the end of its block:
using (var c1 = new C1()) {
// do stuf with c1 here
} // at this point c1.Dispose() is automatically called
The garbage collector knows when there are no references any more to objects, and as far as I know, it even destroys objects that are only referenced by another.
That means that if you dereference objObjectToClassA (set it to null), that both objects will get destroyed, if there are no more references to either of the objects. Simply letting it go out of scope is enough too.
In effect, yes it will also destroy objectToClass1, but not immediately. In this case, setting the variable to null means that your application is no longer using that object, and hence it's eligible for garbage collection. Thinking about it simplistically (I'm sure the GC is smarter than this), once objectToClassA is collected then objectToClass1 is no longer referenced and will also be collected.
Joey's comments about IDisposable are definitely worth bearing in mind; try not to think in terms of finalisers for C# as you don't have control over when they run. Using IDisposable will give you the control that you need in order to tidy up resources.
Destroy is the wrong word, C# (as far as I know) does not have destructors in the C++ sense. No longer used objects are collected/"destroyed" by the garbage collector.
If no other reference to objObjectToClass1 is kept, objObjectToClass1 can also be collected if you set objObectToClassA to null
Should you set all the objects to null (Nothing in VB.NET) once you have finished with them?
I understand that in .NET it is essential to dispose of any instances of objects that implement the IDisposable interface to release some resources although the object can still be something after it is disposed (hence the isDisposed property in forms), so I assume it can still reside in memory or at least in part?
I also know that when an object goes out of scope it is then marked for collection ready for the next pass of the garbage collector (although this may take time).
So with this in mind will setting it to null speed up the system releasing the memory as it does not have to work out that it is no longer in scope and are they any bad side effects?
MSDN articles never do this in examples and currently I do this as I cannot
see the harm. However I have come across a mixture of opinions so any comments are useful.
Karl is absolutely correct, there is no need to set objects to null after use. If an object implements IDisposable, just make sure you call IDisposable.Dispose() when you're done with that object (wrapped in a try..finally, or, a using() block). But even if you don't remember to call Dispose(), the finaliser method on the object should be calling Dispose() for you.
I thought this was a good treatment:
Digging into IDisposable
and this
Understanding IDisposable
There isn't any point in trying to second guess the GC and its management strategies because it's self tuning and opaque. There was a good discussion about the inner workings with Jeffrey Richter on Dot Net Rocks here: Jeffrey Richter on the Windows Memory Model and
Richters book CLR via C# chapter 20 has a great treatment:
Another reason to avoid setting objects to null when you are done with them is that it can actually keep them alive for longer.
e.g.
void foo()
{
var someType = new SomeType();
someType.DoSomething();
// someType is now eligible for garbage collection
// ... rest of method not using 'someType' ...
}
will allow the object referred by someType to be GC'd after the call to "DoSomething" but
void foo()
{
var someType = new SomeType();
someType.DoSomething();
// someType is NOT eligible for garbage collection yet
// because that variable is used at the end of the method
// ... rest of method not using 'someType' ...
someType = null;
}
may sometimes keep the object alive until the end of the method. The JIT will usually optimized away the assignment to null, so both bits of code end up being the same.
No don't null objects. You can check out https://web.archive.org/web/20160325050833/http://codebetter.com/karlseguin/2008/04/28/foundations-of-programming-pt-7-back-to-basics-memory/ for more information, but setting things to null won't do anything, except dirty your code.
Also:
using(SomeObject object = new SomeObject())
{
// do stuff with the object
}
// the object will be disposed of
In general, there's no need to null objects after use, but in some cases I find it's a good practice.
If an object implements IDisposable and is stored in a field, I think it's good to null it, just to avoid using the disposed object. The bugs of the following sort can be painful:
this.myField.Dispose();
// ... at some later time
this.myField.DoSomething();
It's good to null the field after disposing it, and get a NullPtrEx right at the line where the field is used again. Otherwise, you might run into some cryptic bug down the line (depending on exactly what DoSomething does).
Chances are that your code is not structured tightly enough if you feel the need to null variables.
There are a number of ways to limit the scope of a variable:
As mentioned by Steve Tranby
using(SomeObject object = new SomeObject())
{
// do stuff with the object
}
// the object will be disposed of
Similarly, you can simply use curly brackets:
{
// Declare the variable and use it
SomeObject object = new SomeObject()
}
// The variable is no longer available
I find that using curly brackets without any "heading" to really clean out the code and help make it more understandable.
In general no need to set to null. But suppose you have a Reset functionality in your class.
Then you might do, because you do not want to call dispose twice, since some of the Dispose may not be implemented correctly and throw System.ObjectDisposed exception.
private void Reset()
{
if(_dataset != null)
{
_dataset.Dispose();
_dataset = null;
}
//..More such member variables like oracle connection etc. _oraConnection
}
The only time you should set a variable to null is when the variable does not go out of scope and you no longer need the data associated with it. Otherwise there is no need.
this kind of "there is no need to set objects to null after use" is not entirely accurate. There are times you need to NULL the variable after disposing it.
Yes, you should ALWAYS call .Dispose() or .Close() on anything that has it when you are done. Be it file handles, database connections or disposable objects.
Separate from that is the very practical pattern of LazyLoad.
Say I have and instantiated ObjA of class A. Class A has a public property called PropB of class B.
Internally, PropB uses the private variable of _B and defaults to null. When PropB.Get() is used, it checks to see if _PropB is null and if it is, opens the resources needed to instantiate a B into _PropB. It then returns _PropB.
To my experience, this is a really useful trick.
Where the need to null comes in is if you reset or change A in some way that the contents of _PropB were the child of the previous values of A, you will need to Dispose AND null out _PropB so LazyLoad can reset to fetch the right value IF the code requires it.
If you only do _PropB.Dispose() and shortly after expect the null check for LazyLoad to succeed, it won't be null, and you'll be looking at stale data. In effect, you must null it after Dispose() just to be sure.
I sure wish it were otherwise, but I've got code right now exhibiting this behavior after a Dispose() on a _PropB and outside of the calling function that did the Dispose (and thus almost out of scope), the private prop still isn't null, and the stale data is still there.
Eventually, the disposed property will null out, but that's been non-deterministic from my perspective.
The core reason, as dbkk alludes is that the parent container (ObjA with PropB) is keeping the instance of _PropB in scope, despite the Dispose().
Stephen Cleary explains very well in this post: Should I Set Variables to Null to Assist Garbage Collection?
Says:
The Short Answer, for the Impatient
Yes, if the variable is a static field, or if you are writing an enumerable method (using yield return) or an asynchronous method (using async and await). Otherwise, no.
This means that in regular methods (non-enumerable and non-asynchronous), you do not set local variables, method parameters, or instance fields to null.
(Even if you’re implementing IDisposable.Dispose, you still should not set variables to null).
The important thing that we should consider is Static Fields.
Static fields are always root objects, so they are always considered “alive” by the garbage collector. If a static field references an object that is no longer needed, it should be set to null so that the garbage collector will treat it as eligible for collection.
Setting static fields to null is meaningless if the entire process is shutting down. The entire heap is about to be garbage collected at that point, including all the root objects.
Conclusion:
Static fields; that’s about it. Anything else is a waste of time.
There are some cases where it makes sense to null references. For instance, when you're writing a collection--like a priority queue--and by your contract, you shouldn't be keeping those objects alive for the client after the client has removed them from the queue.
But this sort of thing only matters in long lived collections. If the queue's not going to survive the end of the function it was created in, then it matters a whole lot less.
On a whole, you really shouldn't bother. Let the compiler and GC do their jobs so you can do yours.
Take a look at this article as well: http://www.codeproject.com/KB/cs/idisposable.aspx
For the most part, setting an object to null has no effect. The only time you should be sure to do so is if you are working with a "large object", which is one larger than 84K in size (such as bitmaps).
I believe by design of the GC implementors, you can't speed up GC with nullification. I'm sure they'd prefer you not worry yourself with how/when GC runs -- treat it like this ubiquitous Being protecting and watching over and out for you...(bows head down, raises fist to the sky)...
Personally, I often explicitly set variables to null when I'm done with them as a form of self documentation. I don't declare, use, then set to null later -- I null immediately after they're no longer needed. I'm saying, explicitly, "I'm officially done with you...be gone..."
Is nullifying necessary in a GC'd language? No. Is it helpful for the GC? Maybe yes, maybe no, don't know for certain, by design I really can't control it, and regardless of today's answer with this version or that, future GC implementations could change the answer beyond my control. Plus if/when nulling is optimized out it's little more than a fancy comment if you will.
I figure if it makes my intent clearer to the next poor fool who follows in my footsteps, and if it "might" potentially help GC sometimes, then it's worth it to me. Mostly it makes me feel tidy and clear, and Mongo likes to feel tidy and clear. :)
I look at it like this: Programming languages exist to let people give other people an idea of intent and a compiler a job request of what to do -- the compiler converts that request into a different language (sometimes several) for a CPU -- the CPU(s) could give a hoot what language you used, your tab settings, comments, stylistic emphases, variable names, etc. -- a CPU's all about the bit stream that tells it what registers and opcodes and memory locations to twiddle. Many things written in code don't convert into what's consumed by the CPU in the sequence we specified. Our C, C++, C#, Lisp, Babel, assembler or whatever is theory rather than reality, written as a statement of work. What you see is not what you get, yes, even in assembler language.
I do understand the mindset of "unnecessary things" (like blank lines) "are nothing but noise and clutter up code." That was me earlier in my career; I totally get that. At this juncture I lean toward that which makes code clearer. It's not like I'm adding even 50 lines of "noise" to my programs -- it's a few lines here or there.
There are exceptions to any rule. In scenarios with volatile memory, static memory, race conditions, singletons, usage of "stale" data and all that kind of rot, that's different: you NEED to manage your own memory, locking and nullifying as apropos because the memory is not part of the GC'd Universe -- hopefully everyone understands that. The rest of the time with GC'd languages it's a matter of style rather than necessity or a guaranteed performance boost.
At the end of the day make sure you understand what is eligible for GC and what's not; lock, dispose, and nullify appropriately; wax on, wax off; breathe in, breathe out; and for everything else I say: If it feels good, do it. Your mileage may vary...as it should...
I think setting something back to null is messy. Imagine a scenario where the item being set to now is exposed say via property. Now is somehow some piece of code accidentally uses this property after the item is disposed you will get a null reference exception which requires some investigation to figure out exactly what is going on.
I believe framework disposables will allows throw ObjectDisposedException which is more meaningful. Not setting these back to null would be better then for that reason.
Some object suppose the .dispose() method which forces the resource to be removed from memory.
In C#, is it necessary to assign an object variable to null if you have finished using it, even when it will go out of scope anyway?
No, and that could in fact be dangerous and bug-prone (consider the possibility that someone might try to use it later on, not realizing it had been set to null). Only set something to null if there's a logical reason to set it to null.
What matters more IMO is to call Dispose on objects that implement IDisposable.
Apart from that, assigning null to reference variables will just mean that you are explicitly indicating the end of scope — most of the time, it's just a few instructions early (for example, local variables in the method body) — with the era of compiler/JIT optimizations, its quite possible that runtime would do the same, so you really don't get anything out of it. In a few cases, such as static variables etc, whose scope is application level, you should assign a variable to null if you are done using it so that object will get garbage collected.
Should you turn off your car before pushing it to the lake?
No. It is a common mistake, but it doesn't make any difference. You aren't setting the object to null, just one reference to it - the object is still in memory, and must still be collected by the garbage collector.
Most of these responses have the right answer, but for the wrong reasons.
If it's a local variable, the variable will fall off the stack at the end of the method and therefore the object it was pointing to will have one less reference. If that variable was the only reference to the object, then the object is available for GC.
If you set the variable to null (and many who do were taught to do it at the end of the method) then you could actually wind up extending the time the object stays in memory because the CLR will believe that the object can't be collected until the end of the method because it sees a code reference to the object way down there. However, if you omit the setting of null the CLR can determine that no more calls for the object appear after a certain point in your code and, even though the method hasn't completed yet, the GC can collect the object.
Assigning to null is generally a bad idea:
Conceptually, it's just pointless.
With many variables, you could have enough extra assignments to null that you appreciably increase the size of the method. The longer the source code for something is, the more mental effort is taken to read it (even if much of it is just stuff that can be filtered out) and the easier it is to spot a bug. Make code more verbose than necessary only when doing so makes it more understandable.
It is possible that your null assignment won't be optimised away. In that case it's possible that the compiled code won't do the real deallocation until it actually reaches that null assignment, whereas in most cases once the variable is going to do nothing else other than fall out of scope (and sometimes even before) it can be deallocated. You can therefore have a very minor performance impact.
The only time I would assign something to null to "clear" a variable that will no longer be used, rather than because null is actually a value I explicitly want to assign, is in one of the two possible cases:
It is a member of a possibly long-lived object, will no longer be used by that object, and is of considerable size. Here assigning to null is an optimisation.
It is a member of a possibly long-lived object, will no longer be used by that object, and has therefore been disposed to release its resources. Here assigning to null is a matter of safety as it can be easier to find a case where one accidentally uses a null object than where one accidentally uses a disposed object.
Neither of these cases apply to local variables, only to members, and both are rare.
No. When it comes to local variables it makes no difference at all if you have a reference to the object or not, what matters is if the reference will be used or not.
Putting an extra null assignment in the code doesn't hurt performance much, and it doesn't affect memory management at all, but it will add unmotivated statements to the code that makes it less readable.
The garbage collector knows when the reference is used the last time in the code, so it can collect the object as soon as it's not needed any more.
Example:
{
// Create an object
StringBuilder b = new StringBuilder();
b.Append("asdf");
// Here is the last use of the object:
string x = b.ToString();
// From this point the object can be collected whenever the GC feels like it
// If you assign a null reference to the variable here is irrelevant
b = null;
}
For an object which has to implement IDisposable, as a practice I set all members to null in the implementation of IDisposable.
In the distant past I found this practice drastically improved the memory consumption and performance of a .NET Compact Framework application running on Windows Mobile. I think the .NET Compact Framework at the time probably had a very minimalistic implementation of the garbage collector compared to the main .NET Framework and the act of decoupling objects in the implementation of IDisposable helped the GC on the .NET Compact Framework do its thing.
An additional reason for this practice is after IDisposable has been executed on an object, it's actually undesirable for anything to attempt to use any of the members on a disposed object. Sure ideally you'd want an ObjectDisposedException out of an object which has been disposed when something attempts to access any of it's functions, but in place of that a NullReferenceException is better than no exception at all. You want to know about code messing with disposed objects as fooling around with unmanaged resources that have been released is something that can get an application into a lot of trouble.
NOTE: I'm definitely not advocating implementing IDisposable on an object for no other reason than to set members to null. I'm talking about when you need to implement IDisposable for other reasons, i.e. you have members which implement IDisposable or your object wraps unmanaged resources.
I'd just like to add that AFAIK this was only a valid pattern for one point release of Visual Basic, and even that was somewhat debatable. (IIRC it was only for DAO objects.)
Recently discovered that the variables inside ToGadget, and presumably the delegate as well, weren't getting garbage collected. Can anyone see why .NET holds a reference to this? Seems that the delegate and all would be marked for garbage collection after Foo ends. Literally saw Billions in memory after dumping the heap.
Note: 'result.Things' is a List<Gadget> () and Converter is a System delegate.
public Blah Foo()
{
var result = new Blah();
result.Things = this.Things.ConvertAll((new Converter(ToGadget)));
return result;
}
.................
public static Gadget ToGadget(Widget w)
{
return new Gadget(w);
}
Update: changing the 'ConvertAll' to this cleans up the delegates and corresponding object references. This suggests to me that either List<> ConvertAll is somehow holding on to the delegate or I don't understand how these things are garbage collected.
foreach (var t in this.Things)
{
result.Things.Add(ToGadget(t));
}
Use a memory profiler.
You can ask on StackOverflow all day and get a bunch of educated guesses, or you can slap a memory profiler on your application and immediately see what is rooted and what is garbage. There are tools available that are built specifically to solve your exact problem quickly and easily. Use them!
There is one major flaw in your question, which may be the cause of confusion:
Seems that the delegate and all would be marked for garbage collection after Foo ends.
The CLR doesn't "mark items" for collection at the end of a routine. Rather, once that routine ends, there is no longer an (active) reference to any of the items referenced in your delegate. At that point, they are what is refered to as "unrooted".
Later, when the CLR determines that there is a certain amount of memory pressure, the garbage collector will execute. It will search through and find all unrooted elements, and potentially collect them.
The important distinction here is that the timing is not something that can be predicted. The objects may never be collected until your program ends, or they may get collected right away. It's up to the system to determine when it will collect. This doesn't happen when Foo ends - but rather at some unknown amount of time after Foo ends.
Edit:
This is actually directly addressing your question, btw. You can see if this is the issue by forcing a garbage collection. Just add, after your call to Foo, a call to:
GC.Collect();
GC.WaitForPendingFinalizers();
Then do your checking of the CLR's heap. At this point, if you're still getting objects in the heap, it's because the objects are still being rooted by something. Your simplified example doesn't show this happening, but as this is a very simplified example, it's difficult to determine where this would happen. (Note: I don't recommend keeping this in your code, if this is the case. Calling GC.Collect() manually is almost always a bad idea...)
It looks like your function is set up to return the new Blah(). Is it actually being returned in your code? I see in the piece you posted that it is not. If that is the case, then the new Blah() would have a scope outside of Foo and it may be the calling function that is actually holding the references in scope. Also, you're creating new Gadget() as well. Depending on how many Blahs to Gadgets you have, you could be exponentially filling your memory as the Gadgets will be scoped with the Blahs which are then held in scope beyond Foo.
Whether I'm right or wrong, this possibility was kinda funny to type.
None of the guides/notes/articles that discuss IDisposable pattern suggest that one should set the internal members to null in the Dispose(bool) method (especially if they are memory hogging beasts).
I've come to realize the importance of it while debugging an internal benchmark tool. What used to happen was that, there was this buffer that contained a big array inside it. We used to use a static buffer for the whole benchmark program. Once we're done with the buffer, there was no way we could release this internal array, neither could we make this buffer releasable (as it was static).
So, I believe that, after Dispose() is called, the class should do everything it can so that it releases all the resources it is using and make them available again, even if the object being disposed itself is not collected back by GC, and not setting members to null, thereby, not allowing the internal objects to be collected by the GC implies that the Dispose implementation is not perfect.
What's your opinion on this ?
Releasing any additional references during Dispose is certainly something I try to do, for two reasons:
it allows the inner objects to be garbage collected even if the disposed object is still in scope
if the inner objects are disposable, it means we only dispose them once even if Dispose() is called repeatedly on the outer object
For example, I tend to use things like:
if(someDisposableObject != null)
{
someDisposableObject.Dispose();
someDisposableObject = null;
}
(for non-disposable, just set to null)
someNonDisposableObject = null; // etc
You might also want to set any events to null:
someEventHandler = null;
This can help minimise the impact if the caller can't fully release their reference (or simply forgets) at the moment. While you should try to release the outer object (for GC), it is relatively easy to accidentally extend the life of the object, for example via a captured variable (anonymous method/lambda), an event, etc.
If you have a finalizer, then during the GC process there is no benefit doing this, and you shouldn't really call methods on external objects (even Dispose()) - so in short: don't do any of this during a GC sweep.
Maybe I'm missing your point, but once your object is disposed, the root or 'sub-root' it represented relative to it's members has been detached. It seems like you are thinking of garbage collection like a ref count system (which can be done, but ... usually isn't).
Instead, think of it as a many-rooted tree, where every object has branches for what it links to. At the end of the day the 'final roots' are statics and anything instantiated from a 'main' loop.
When the garbage collector runs, the easiest way to think about what it does is to consider that it will walk the list of 'real roots' and apply a 'color' to everything it can 'reach'.
Now, assumed the collector has access to 'everything', whether it was rooted or not. Anything not colored can be cleaned up.
Getting back to your original question, when your object is disposed, one assumes (or at least hopes) that no one references it anymore. If this is the case, it is no longer rooted, and so it will not contribute to 'coloring' anything it touches.
Long story longer - if nulling out members in a Dispose routine is fixing something - I would be you have a different, and real, problem that someone is holding a link to your disposed object, and keeping it 'reachable' when it should not be.
I apologize for what may be the most over-quote-filled message I've ever written, but I'm sort of abusing standard terms.
Well, generally, it's not going to make a difference. The only place where it will make a difference is when you have a reference to an object on the Large Object Heap, the behavior of which you have seen already).
There is a good article on the LOH which goes into this in more detail here:
http://msdn.microsoft.com/en-us/magazine/cc534993.aspx