-
March 7th, 2008, 10:23 AM
#1
Reuse a pointer or use a new one in a loop
Hi,
I wonder what is the most memory and processor efficient solution. Also, which is considered the most appropriate, and why?
My example is simple. I have a loop. In the loop I need a new instance of a class for each turn in the loop. I don't need it outside the loop, I don't even need it outside each turn.
Should I place the pointer outside the loop and in each turn assign it to a newly instantiated class.
Or should I place it inside the loop.
Should at either solution trigger the gc somehow to gain RAM?
etc etc
All info you can share on this is much appreciated!
I come from unmanaged C++ and don't really know how to use the gc the most optimum way.
I mostly work with CompactFramework so comments regarding any difference in procedures compared to standard .NET Framework is also appreciated.
For instance (pseudo code just to show what I mean):
MyClass mc = null;
for (int i=0; i < 10; i++)
{
mc = new MyClass(i);
mc.Show();
// at this point I have no further interest in the instantiated mc
}
or
for (int i=0; i < 10; i++)
{
MyClass mc = new MyClass(i);
mc.Show();
// at this point I have no further interest in the instantiated mc
}
Thanks!
-
March 7th, 2008, 11:14 AM
#2
Re: Reuse a pointer or use a new one in a loop
The perform identically with respect to memory usage and garbage collections. There is one difference, but only a tiny tiny one.
If you declare the variable outside of the loop, like in case 1, when the loop finishes iterating, the last object you instantiate will still have a valid reference held on it. This means that unless you manually set mc = null, you can't GC the object until the method exits.
If you declare the variable inside the loop, then as soon as the loop ends, the variable is out of scope and the last object you instantiated might become eligible for GC immediately.
It depends on the compiler aswell i suppose. They could both result in identical code for all i know, but from this high-level perspective, that's the only difference i can see.
So other than style differences, i can't see much of a difference. I'd recommend inside the loop purely as a style thing. If it's only used there, then only have it available there.
www.monotorrent.com For all your .NET bittorrent needs
NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.
-
March 7th, 2008, 11:39 AM
#3
Re: Reuse a pointer or use a new one in a loop
If you declare the variable outside of the loop, like in case 1, when the loop finishes iterating, the last object you instantiate will still have a valid reference held on it. This means that unless you manually set mc = null, you can't GC the object until the method exits.
True in debug builds, not in release builds.
In debug builds the lifetimes of objects are extended to the end of their scope. This is so that you can 'watch' a variable until its scope ends.
In release builds an object is marked for garbage collection after it's last reference in the code.
e.g.
Code:
{
string helloThere = "hello there";
// .. some code ..
Console.WriteLine(helloThere);
<---- This is last reference of 'helloThere' so in release builds it's marked for GC here
// .. some code which doesn't use 'helloThere'
} <--- in debug builds 'helloThere' is kept alive until the scope ends.
Darwen.
-
March 7th, 2008, 12:32 PM
#4
Re: Reuse a pointer or use a new one in a loop
The only way that could happen would be if in release mode the compiler inserted an explicit call to 'helloThere = null' right after the last place the variable is referenced. Some might argue that adding explicit calls to make null out references would result in slightly slower code.
www.monotorrent.com For all your .NET bittorrent needs
NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.
-
March 7th, 2008, 02:49 PM
#5
Re: Reuse a pointer or use a new one in a loop
What you say sounds logicaly and consistent with common knowleadge of how GC works, but it seems that Darwen is true. Look at GC.KeepAlive() method and what MSDN says about it. If you would be true, the GC.KeepAlive() will be worthless. That's my opinion.
Last edited by boudino; March 7th, 2008 at 02:51 PM.
Reason: Formatting fixed
- Make it run.
- Make it right.
- Make it fast.
Don't hesitate to rate my post. ![Thumb](images/smilies/thumb.gif)
-
March 7th, 2008, 03:40 PM
#6
Re: Reuse a pointer or use a new one in a loop
See "Applied Microsoft .NET Framework Programming" page 456.
Also here.
In relase builds an object is marked as garbage after the last statement to reference it. You have to watch out for this when doing interop.
Darwen.
-
March 7th, 2008, 03:41 PM
#7
Re: Reuse a pointer or use a new one in a loop
![Quote](images/misc/quote_icon.png) Originally Posted by Mutant_Fruit
So other than style differences, i can't see much of a difference. I'd recommend inside the loop purely as a style thing. If it's only used there, then only have it available there.
I think you can go a tad bit beyond style in supporting the inside the loop model if you consider code consistency/readability as well as for defensive programming considerations.
Consider:
Code:
if ()
{
int TempValue;
// Do stuff
}
// If-block #2 to 20
vs
Code:
int TempValue;
// If-Block #1
...
// If-Block #12
Considering readability and consistency, the first method is much easier to see what is going on. You always know the scope of "TempValue" and what it is each time. If another "If-Block" needs TempValue to be a string, it can use it as such. Looking at your code you would intrinsically understand that "TempValue" is a scratch variable and you wouldn't even need to wonder if it was a member variable or relevant any where else in the method since you clearly see it goes out of scope at the end of each block.
Considering defensive programming, there are mistakes you can not make in the first method that can be a real killer with the second method.
Consider If-Block #12 in the second method:
Code:
// If-Block #12
if ( ... )
{
TempVal += AlienValue * NumberKilled;
...
Score += TempVal * Difficulty + Bonus;
}
TempVal was not set to zero, so it has some 'junk' from the last time it was used. If TempVal was declared in this scope, it would be zero. You do not need to remember to zero it each time you use it.
Now let us consider even more sloppy code:
Code:
{
// Created on January 1.
string Scratch;
// (..) Use Scratch
// (..) Use Scratch
// (..) Use Scratch, Scratch = Player.Name
// (..) #1 to #10, nobody uses scratch.
// SaveGame(Scratch); // Scratch has Player.Name
}
Then in March:
Code:
// (..) #1 to #5, nobody uses scratch.
// (..) #6 Use scratch
// (..) #7 to #10, nobody uses scratch.
Suddenly save games stop working right. Again, if scratch was in side the local scope of these blocks this problem would not exist. You would have been forced to reserve a special variable to use for SaveGame() and not just re-use scratch.
I definitely think using items in the most restrictive scope as possible should be the rule. The only exception is when performance is critical, such as in a rendering loop of a game. For example, if you are creating a rotation matrix that is to be applied in a loop to a bunch of points, creating the matrix each time inside the loop will kill your frame rate. In fact, even just creating a bunch of points like "VertBuff[J] = new vector(X, Y, Z);" Will cause a huge slowdown as the number of points you use increase.
In one case, by simply using some static, read only vectors as a 'base vector' for some rendering stuff my frame-rate went from 5fps to 60fps. I was trying to render about 5000 sprites at once as test when I did that optimization.
-
March 8th, 2008, 07:33 PM
#8
Re: Reuse a pointer or use a new one in a loop
![Quote](images/misc/quote_icon.png) Originally Posted by darwen
In relase builds an object is marked as garbage after the last statement to reference it
Now that's something i didn't know! My undersatnding of the GC was that it scanned all rooted references (which includes structs and all that) and then touched every object that was reachable. Once it found all those, it then moved all touched objects to a specific location in memory and freed the rest. this is how it 'collected' the garbage.
What i assumed happened was that while your object had a valid reference to it in your method (i..e you didnt explicitly null it out), it would then still be 'accessible' when the GC does its stack walk. Obviously not. Well, ya learn something new every day
www.monotorrent.com For all your .NET bittorrent needs
NOTE: My code snippets are just snippets. They demonstrate an idea which can be adapted by you to solve your problem. They are not 100% complete and fully functional solutions equipped with error handling.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|