[C#] GC and .tostring() method

Started by
12 comments, last by SeeMe 17 years, 10 months ago
Hello, I have a simple question : How to avoid a temporary string variable declaration if I want to send a Float variable to a string. Exemple :


float fps;
string strFPS;
fps = 0f;

for (int a = 0; a <= 1000000; a++)
{
   fps++;
   strFPS = ((int)fps).ToString();
}



This simple exemple, will alocate 1000000 temporary string. A a game main boucle it could cause the GC to slow down from time to time to free up some memory ! Is there a way to sent my float value to the global string, without this anoying hiden string creation at each loop iteration ? Tx you !!!
Advertisement
Use the StringBuilder class or write your own int to string function which will write into a fix size buffer.
2+2=5, for big values of 2!
Hello,

It clearly seems that its the .ToString() method the create a temporary String before sending it the Global string.
So StringBuilder can't help me here.

I will have to build a "'number' to string" function that is using a static string for buffering !

Kind regards,
C# strings are immutable (can't be modified once created), so you may wish to store a character array instead. It'll be a bit of a bother, but between a MemoryStream, a StreamWriter and a character array, you should be able to do what you want. Hopefully someone else will know a better way.
If you declare your variable like that:
string strFPS;

you can only change it by creating a new string object and assigning the new string object to strFPS.


If you want to avoid object creation you need a variable of a mutable type like:
StringBuilder strFPS;// stuff here{   strFPS.length=0;   strFPS.append(yourfloat);}
Hello,

Tx for trying, but no, it's not true this code will also instanciate 10.000 temporary string (Following CLR Profiler) :


private StringBuilder sb = new StringBuilder();private int a = 0;public void Run(){   for (int b = 0; b < 10000; b++)   {       sb.Length = 0;       sb.Append(a);   }}


It seems that its the '.ToString()' method from the integer variable that is using a temporary String.

So :

A (Integer) --> Call to .ToString() --> MyTempString with A value --> Sent to StringBuilder !
MSDN on StringBuilder.Append(int)
Quote:Remarks:
Int32.ToString is used to get a string representation of value. The capacity of this instance is adjusted as needed.

That's just stupid :(

You could use StringBuilder.Append(char) and write the int->string conversion yourself, that would probably work.

On the other hand GC for short-lived objects is usually quite cheap, so it might not be worth avoiding it.
Yes indead, it's really strange.

I could let the GC do its job, but when I see the CLRprofiler log it scares me : 100000 string instanciated for a size of 2.6Mbytes every 2 seconds !

It makes 78Mbytes by minutes allocated for .... nothing !
It's allocating a lot for nothing ...

There are all kinds of tricks involved in writing garbage collectors - one of them is to exploit the knowledge that the longer an object has been in use, the less likely it is to need garbage collecting - which would make a well written GC perform well in the case you describe.

In general, write C# and let the GC do it's job for most code and write C++ for time critical code (and hook them together using C++CLR).

the same would happen if you used a std::string declared in a function. It would get created and destroyed, but allocated and deallocated quickly.

Because the string object is a class rather then a struct, it is likely that it's stored in the heap (I dunno, the CLR might make exceptions / specific optimisations for the string class). But because the graph is shallow (as it's declared in the function) it is easy for the GC to pick up in a single pass. It's the longer lived memory allocations you need to be careful of.

For instance "string strFPS;" - you only need to declare strFPS if you intend on using it more then once. Otherwise just send it across to another function with a .ToString(), so the instance is just anon.

To make your code friendlier for the GC, try and keep as few references to the string as possible. The less references to a variable it has to check, the more likely it can get rid of it quickly.

Unless your applications memory footprint is steadily climbing just from your original example, there is no need to stress out about this stuff.

It's good you are using the CLR profiler and all that, but I would worry about this issue only if it becomes apparent that it is a problem later on when more of your game is done. There is always a danger of focusing too much on this kind of thing when it's not really a problem - it's just different from what you are used too.

I think the biggest problem some of the C++ guys have when it comes to C#, Java and the like is trusting what is going on behind the scenes because they are so used to controlling every single detail. I know it took me a while to get used to the idea, and learn optimisation techinques for C# that might not make sense in C++.

A general rule of thumb applies - do timings etc to see what the effect of things is. Just looking at the allocated / destroyed metric on it's own could be misleading without time taken to complete a loop and interuptions of the GC. So I would try and put this to the back of your mind and just get on with whatever you are doing.
Anything posted is personal opinion which does not in anyway reflect or represent my employer. Any code and opinion is expressed “as is” and used at your own risk – it does not constitute a legal relationship of any kind.

This topic is closed to new replies.

Advertisement