C# The 'new' keyword on existing objects - c#

I was wondering as to what happens to an object (in C#), once its reference becomes reassigned. Example:
Car c = new Car("Red Car");
c = new Car("Blue Car");
Since the reference was reused, does the garbage collector dispose / handle the 'Red Car' after it's lost its reference? Or does a separate method need to be implemented to dispose of the 'red car'?
I'm primarily wondering because there's a relatively large object that I'm going to recycle, and need to know if there is anything that should be done when it gets recreated.

In your example, the Red Car instance of c will become eligible for garbage collection when c is assigned to Blue Car. You don't need to do anything.
Check out this (old, but still relevant) MSDN article about the .NET garbage collector. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
The first paragraph says it all:
Garbage collection in the Microsoft .NET common language runtime environment completely absolves the developer from tracking memory usage and knowing when to free memory.

Since the reference was reused, does the garbage collector dispose / handle the 'Red Car' after it's lost it's reference?
You're looking at this in perhaps the wrong way:
c [*] ----> [Car { Name = "Red Car" }] // Car c = new Car("Red Car")
Then your next step:
c [*] [Car { Name = "Red Car" }] // No chain of references to this object
\------> [Car { Name = "Blue Car" }] // c = new Car("Blue Car")
The GC will come along and "collect" any of these objects which have no chain of references to a live object at some point in the future. For most tasks, as long as you're using managed data, you should not worry about large objects versus small objects.
For most tasks you only worry about deterministic memory management when dealing with IDisposable. As long as you follow the best practice of using-blocks, you will generally be fine.

You create a new object and assign a reference to it to your variable c. At the same time the previous object (the "red car") is now not referenced anymore and may be garbage collected.

If there are no other references to Red car, it will be collected by the GC on its next cycle. You don't need anything extra (unless it's a class that has streams etc. that need to be disposed)

The garbage collector will handle cleanup for the red car when it is not longer rooted (not reachable). You, the developer, don't generally have to worry about cleaning up memory in .Net.
There are three caveats that need to be mentioned:
It won't happen right away. Garbage collection will happen when it happens. You can't predict it.
If the type implements IDisposable, it's up to you to make sure the .Dispose() method is called. A using statement is a good way to accomplish this.
You mentioned it's a large object. If it's more than 85000 bytes it will stored in a place called the Large Object Heap, which has very different rules for garbage collection. Allowing this kind of object to be recycled frequently can cause problems.

Garbage collector will take care of disposing of Car object

The GC will pick up your Red Car object and dispose of it.
You can call a custom destructor or implement IDisposable if you have resources that need to be released when the original object is no longer used.

In case Car holds some native resources you'll want to implement IDisposable and dispose of it properly before reusing the variable.

I think you should implement the IDispose interface to clean up unmanaged resources
public class car : IDispose

Related

Destructors in .NET

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

Possible to force an object to be garbage collected in Gen 1 or Gen 2 and not in Gen 0?

An interviewer asked me a weird question of which I couldn't find answer.
Is it possible to force an object to be garbage collected in Gen 1 or Gen 2 and not in Gen 0?
Yes.
public class WillAlwaysBeCollectedInGen1or2
{
~WillAlwaysBeCollectedInGen1or2()
{
}
}
Because it has a finaliser, and no code that ever calls GC.SuppressFinalize(this), then it will always end up in the finalisation queue instead of being collected when it first becomes eligible for collection, which means it will always be collected in a generation other than the first.
Of course, since we generally want the opposite to happen (objects are collected as soon as possible) this shows why one should not define a finaliser unless it's actually needed, and should always call GC.SuppressFinalize(this) if an object is in a state where finalisation doesn't do anything useful (most obviously if it's been disposed of explicitly, but there can be other cases).
So, the usefulness of this knowledge is this; in knowing what not to do.
By extension, you can force an arbitrary object to be collected in Gen1 or Gen2 only by holding a strong reference to it in such an object:
public class PreventGen0Collection
{
private object _keptAlive;
public PreventGen0Collection(object keptAlive)
{
_keptAlive = keptAlive;
}
~PreventGen0Collection()
{
}
}
Because PreventGen0Collection is itself prevented from collection until at least Gen 1, as explained above, the object passed to its constructor is kept from even being eligible for collection on a GC sweep, and will hence be promoted to the next generation.
Again, this demonstrates code to avoid; being finalisable causes not just an object to be promoted, but a whole graph. Never use finalisers when you don't need to, and suppress finalisation when you can.
You can't... But you can extend the life of an object until some point. The simplest way inside a method is to have a:
var myObject = new MyObject();
... some code
... some other code
// The object won't be colleted until this point **at least**
GC.KeepAlive(myObject)
Or you can use GCHandle:
var myObject = new MyObject();
this.Handle = GCHandle.Alloc(new object(), GCHandleType.Normal);
(where this.Handle is a field of your object)
and perhaps in another method:
this.Handle.Free();
The description of GCHandleType.Normal is:
You can use this type to track an object and prevent its collection by the garbage collector. This enumeration member is useful when an unmanaged client holds the only reference, which is undetectable from the garbage collector, to a managed object.
Note that if you do this (the GCHandle "this") inside a class, you should implement the IDisposable pattern to free the this.Handle.
Ok... Technically you could:
var myObject = new MyObject();
GC.Collect(0); // collects all gen0 objects... Uncollected gen0 objects become gen1
GC.KeepAlive(myObject);
Now myObject is gen1... But this won't really solve your problem :-)
According to the documentation of GC.Collect:
Forces an immediate garbage collection of all generations.
Then yes, you can do that. Simply force a collection.
As described here, Fundamentals of Garbage Collection, under Survival and promotions:
Objects that are not reclaimed in a garbage collection are known as survivors, and are promoted to the next generation.
As such, if the object was in generation 0 before you forced a collection, it will now be in generation 1.
OK, and then, what if I don't have a reference to the object any more? What happens if I force a collection then? Well, most likely it will be collected. Can it be fixed? Well, depends on what you mean by "fixed", but yes.
Add a finalizer to the object. A finalizer will make the object be moved on to a separate list during collection, ready for the finalizer thread to finalize it. Only after the finalizer has processed it will it again be eligible for collection but by then it has already been promoted.
Also note that if you add the finalizer because you need to handle the case of not having a reference you don't really need to force the collection any more since this is an interview question with a very specific problem, you have now guaranteed that it will survive generation 0.
So two steps, either of which will guarantee that the object is not collected in generation 0:
Add a finalizer
Hold on to a reference to the object and force a collection.
Caveat: Garbage collection is documented, but have been tuned various ways and times during the life of .NET. Whether the documentation and above text can be taken as documentation fixed in stone or whether there are optimizations done here that can for instance make GC.Collect not force a collection because a collection is already in progress I don't know.
Since you asked in the context of an interview I would say the above should be your answer to the interviewer, but don't rely on any of this in practice.
GUIDELINE: Relying on the internals of the garbage collectors is one way to make brittle code.
DON'T DO IT.
The only place I've seen good reasons for actually messing with GC.Collect, and even there it is dubious, is in a more or less single-threaded system that deals in big batches. For instance a Windows service that processes big batches of data periodically could do one batch, then force a collection to reduce memory footprint until the next batch comes due.
However, this is a highly specialized case. Other than satisfying an interviewer, GC.Collect should not (as a guideline) be present in your production code.

What happens to 'object' after local scope?

I am eager to know what happens to a object in .NET when it falls out of scope. Something like this:
class A
{
ClassB myObjectB = new ClassB();
}
//what happens to object at this point here?
What happens in the memory? Does GC get called when it falls out of scope and loose it reference in the heap?
What happens in the memory? Does GC get called when it falls out of scope and loose it reference in the heap?
No - the GC doesn't get called at this point.
What happens is that the object is left in memory, but is now "unrooted" - basically, there are no references to that object from any other object. As such, the object is now eligible for garbage collection.
At some point in the future, the GC will run. When this happens, the unrooted object will now be eligible for garbage collection. Depending on which generation holds the object, it may or may not be cleaned at that point. Eventually, if the program continues executing and if memory pressure causes the appropriate generation to be collected, the memory for that object will be reclaimed.
There is no definite point in time when this will happen (unless you explicitly call GC.Collect, which is a bad idea). However, with managed code, you don't really need to worry about when this will happen. Just assume that it will happen when and if appropriate for your specific application.
Following from pst's comment, a better example might be this:
void M()
{
ClassB myObjectB = new ClassB();
}
//what happens to object at this point here?
In this example, myObjectB is a local variable rather than a field. So, what happens when the local variable goes out of scope? Nothing! Scope has nothing to do with object lifetime in C#.
What really happens is that the JIT compiler decides to release the object at some point. That can be before the end of the variable's scope, if the variable is not going to be used in the rest of the method. Once the object is no longer referenced, as other answers have also mentioned, it becomes eligible for collection by the GC. It is not actually collected until the GC runs (actually, until the GC collects the generation in which the object is living).
As pst implied, a field is a poor example because it will always be reachable whenever its containing object is reachable, so the separation between scope and object lifetime is even greater:
class A
{
private object o = //whatever
}
void B()
{
var a = new A();
// here, the field o is not in scope, but the object it refers to is reachable and cannot be collected.
GC.KeepAlive(a);
}
I find "falling out of scope" to be a much more C++-specific way of thinking of things, where at the end of a given scope an object with automatic storage is freed and has its destructor called.
In the C# world, there's no "falling out of scope". Variables (read: names) exist in a certain scope, and that's it. The GC really has no concern for this; an object can be collected before the end of its name's scope even exits, or long afterwards depending on what references it and when the GC decides a collection is necessary.
The two concepts should then be divorced and reasoned about separately. Scoping is all about names, whereas garbage collection cares only about the reachability of objects. When an object is no longer reachable from one of the known roots, it will be scheduled for collection.
If there's nothing referencing the object, it gets eventually collected by GC. The thing is, you can't predict WHEN exactly it will happen. You just know, it will happen.
Generally speaking, Garbage Collection happens at 3 distinct generations (0, 1, or 2). When each of these is collected depends on how much resources are needed by the OS.
A call to GC.Collect() will collect all of the available resources but it is possible to define which generation of resources to collect.

Do you need to dispose of objects and set them to null?

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.

C#: Is there an Advantage to Disposing Resources in Reverse Order of their Allocation?

Many years ago, I was admonished to, whenever possible, release resources in reverse order to how they were allocated. That is:
block1 = malloc( ... );
block2 = malloc( ... );
... do stuff ...
free( block2 );
free( block1 );
I imagine on a 640K MS-DOS machine, this could minimize heap fragmentation. Is there any practical advantage to doing this in a C# /.NET application, or is this a habit that has outlived its relevance?
If your resources are created well, this shouldn't matter (much).
However, many poorly created libraries don't do proper checking. Disposing of resources in reverse of their allocation typically means that you're disposing of resource dependent on other resources first - which can prevent poorly written libraries from causing problems. (You never dispose of a resource, then use one that's depending on the first's existence in this case.)
It also is good practice, since you're not going to accidentally dispose a resource required by some other object too early.
Here's an example: look at a database operation. You don't want to close/dispose your connection before closing/disposing your command (which uses the connection).
Don't bother. The GarbageCollector reserves the right to defragment and move objects on the heap, so there's no telling what order things are in.
In addition, if you're disposing A and B and A references B it shouldn't matter if A disposes B when you dispose A, since the Dispose method should be callable more than once without an exception being thrown.
If you are referring to the time the destructor on the objects gets called, then that's up the garbage collector, the programming can have very little influence over that, and it is explicity non-deterministic according to the language definition.
If you are referring to calling IDisposable.Dispose(), then that depends on the behavior of the objects that implement the IDisposable interface.
In general, the order doesn't matter for most Framework objects, except to the extent that it matters to the calling code. But if object A maintains a dependency on object B, and object B is disposed, then it could very well be important not to do certain things with object A.
In most cases, Dispose() is not called directly, but rather it is called implicitly as part of a using or foreach statement, in which case the reverse-order pattern will naturally emerge, according to the statement embedding.
using(Foo foo = new Foo())
using(FooDoodler fooDoodler = new FooDoodler(foo))
{
// do stuff
// ...
// fooDoodler automatically gets disposed before foo at the end of the using statement.
}
Nested 'usings' shows you the 'outlived' is not really on, and rarely is (not to go and say never after 40 years of evidence).. And that includes the stack-based VM that runs on say CMOS.
[ Despite some attempts by MSDN.com and Duffius to make it vanish, you know manage it all for you the difference between the heap and stack. What a smart idea.. in space ]
"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."
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
So you can worry about your LIFO dispose semantics as much as you like, but if you leak one, the Dispose()'s are going to be called in whatever order the CLR fancies.
(This is more or less what Will said, above)

Categories