views:

106

answers:

5

Hi,

I have a very basic question.

I write a loop like this:

while(true)
{
   MyTestClass myObject = new MyTestClass();
}
  1. When will be the object created in the loop, garbage collected?
  2. Also, for every iteration, is it that the new memory location is allocated to the myObject reference?
  3. What if i write myObject = null; at the end of every iteration?
+7  A: 
  1. whenever GC feels like it, frankly; the variable is never read, so it is always eligible
  2. myObject is the variable - that has a fixed position on the stack for the reference; however, each new MyTestClass() is a different object, created somewhere in the available heap space; different each time
  3. no difference whatsoever; strictly speaking there are some complexities involving the actual declaration point of the variable (in IL) and how while is actually implemented - but that would only show after exiting the loop. And since on each iteration you immediately allocate it, there is no tangible difference here
Marc Gravell
Are you sure that the variable has necessarily a fixed place every passthrough? Since the variable declaration is within the loop, isn't this a more dynamic scenario where you would be able to capture different "instances" of myObject if you employed them constructing a Lambda expression within the loop that had a lifetime beyond the loop? Or is that a compiler trick?
Tormod
Is it correct that myObject variable has fixed position on the stack? I think, everytime new variable called 'myObject' gets created on stack (and one created in the previous iteration is obviously removed).Am i correct?
Amey
@Tormod in that case storage for a field in the closure for the lambda would be dynamically created, and the field populated by copying the value held in the variable, but that does not effect the location of the variable on the stack.
Pete Kirkham
@Marc Thank you very much.
Amey
@Tormod - as @Pete suggests; if you capture it, it is no longer a "local"; the local stack will instead have a reference to the object that *references* the variable (now a field). Whether you get a different capture-object per loop depends on exactly where the variable is defined; in this case you *would* get a new capture-object per loop. And that capture instance would *also* get collected each time (when the GC feels like it).
Marc Gravell
+4  A: 

When will be the object created in the loop, garbage collected?

At some point after the last reference to it is removed. A new reference is created and removed on each loop iteration, so the GC is free to collect these objects when it wants. In practice, this is likely to happen when your program completely fills generation zero.

Also, for every iteration, is it that the new memory location is allocated to the myObject reference?

Yes.

What if i write myObject = null; at the end of every iteration?

It won't make any difference. Setting myObject = null; removes that reference to the object, but the reference is removed anyway when the myObject variable is reassigned in the next loop iteration.

Tim Robinson
@Tim - just re your last point; at the IL level (which is what GC cares about), scopes don't exist and `myObject` is declared in the IL preamble (assuming it isn't captured), so exists (as a "local" with a value) for the entire duration of the method. It is not explicitly cleared when leaving the (C#) scope. Simply: it is never read past this point.
Marc Gravell
I forgot the IL variable doesn't observe the C# block...
Tim Robinson
+2  A: 

Let's clear a few things up. Every time you hit the inside of the loop, myObject will be allocated to a new address. So all this loop ever does is allocate new memory addresses for a single variable name. Thus:

  1. The GC will garbage collect all of the previous allocations, probably almost immediately since the variable is never used.
  2. Yes.
  3. Doesn't matter. The variable is still unused.
Jon Limjap
A: 

As an addition to all the others answers:

You could make your class a struct. Then it will be on the stack and be thrown away for each iteration. If your struct makes new classes then you are back to square one though. And if your struct is large it could affect performance negatively but otherwise if it is small it could affect the performance positively.

lasseespeholt
That is not correct. If it was a struct it would not be thrown away for each iteration, it would be the same instance for each iteration and not be thrown away until the method exits. It would get a new value for each iteration, though.
Guffa
Does this mean, in case of struct, that the same variable will be used but it will have different values for its attributes in every iteration? i.e. The struct variable declared inside the loop will NOT be removed from stack at the end of each iteration.Am i right?
Amey
Whether loop variables get popped or not is down to the compiler, but the *behaviour* of such variables is that they are reset (brand new) on each iteration. If you want a variable value to survive on iteraions, you need to declare it outside the loop.
Adam
By "thrown away" I just mean you can't access obviously the previous data. Whether it clears the data on the stack or pop the stack and then push the stack is really not significant in regards to GC. The first is a little faster but have the same "flow" as pop/push in regards to GC.
lasseespeholt
+3  A: 

Let's add some code that actually uses the object to make it clearer what really happens:

while(true) {
  // Here a new instance is created in each iteration:
  MyTestClass myObject = new MyTestClass();
  // Here the instance is still in use
  // until here:
  myObject.CallSomething();
  // Here the instance isn't used any more,
  // so the GC can collect it if it wants to.
  // Setting the reference to null here:
  myObject = null;
  // is useless, as the GC already knows that the
  // instance is unused before that time.
}
Guffa
+1 Re your point about null, indeed the runtime will make these elligible for GC as soon as its no longer used - meaning even in large methods where you declare a lot of object variables, nulling them part-way in the method - though readable - incurs no difference in behaviour.
Adam
@Adam: If this is the case, then when should we assign an object the null value? When we know that the variable will not be used after certain line of code (e.g. after myObject.CallSomething()), is it alright to not set it to null?
Amey
@Amey yes, sorry I wasn't very clear - setting it to null is **not** required, the runtime has the intelligence to figure this out for your.
Adam