Efficiency when declaring variables


I’ve researched for a while about the most efficient way to declare variables, and I haven’t found a definitive answer. Some people say that primitive variables like ints and floats are stored in the stack and will live for the entire program execution, no garbage collected, so it doesn’t matter where you declare the variable because they are not instantiated and destroyed continuously in the Update() function.

Method 1

float x;

Update () { x = 1.0f; }

Method 2

Update () {float x = 1.0f;}

Could anybody confirm that both methods make no differences on speed and efficiency?

I wouldn’t bother worrying about efficiency unless I knew it was a problem. Instead I would think about what makes most sense. Declaring a variable as a member means it belongs to the state of the object, and suggests it is shared across calls to the object. Declaring a variable as a local variable in a method clearly states the longevity of the variable to exist for the duration of the call, no further. It has a shorter scope than a member variable (member variables exists for the duration of the object).

Sit back and think if you need that variable to persist over time. Does your class have multiple methods, when which called, require that data to exist? If so, it sounds like a candidate for becoming a member. If not, it sounds like a candidate for becoming a local variable.

So I get you this way; you’re not very interested in software design as much as you are with performance concerns at this point - or the contrary - you want to design your software and feel unsure if your software practices will result in slow code. You want to either solve a concrete, measurable problem or you just want to learn how to squeeze every bit of performance out of your script without knowing if it’s slow or not in the first place, to proactively prevent performance rot.

So apart from the practical and logical reasons where to put variables, let’s think about what implications there are for both approaches:

  • Using a member variable

Each instance of the class will consume 4 bytes extra for storing the value. If you have 1000 objects, you’ll require 4000 bytes memory to hold a float for each instance. Each object will be located “somewhere” in memory. Accessing the memory might cause a cache miss, if the memory was not already cached since before. Unfortunately I haven’t dug deep into the native side to see if the memory implicitly get cached after a call to Update. I would assume Unity still requires base class memory for normal operation so chances are the memory already is cached from prior access. I don’t know about the memory layout for subclasses in detail, but I would imagine that memory is very near the base class memory and could get cached by the CPU.

  • Using a local variable

Each call to the method will reserve 4 byte stack space for the float (this memory is transient and will be freed after method call). This means 1000 objects require no extra memory for each instance. Since Unity is executing Update in the main thread, only one call is generally open at any time, so the program uses 4 bytes stack space at most. To allocate stack space, a register is typically incremented that represent the stack size. To deallocate stack space, the register is typically restored. Stack operations are generally very fast. Since the stack is almost always in use, it’s very likely to be cached when you want to read the variable.

  • So what does it mean?

Well, it means that having a local variable you’re constrained to not being able to store that information between calls. Likely, you’re either dealing with a constant or a query. It communicate to readers of your code that the variable is local to the method, and is not shared between methods. May result with less worries on their mind as they don’t have to trace every method it’s used in. It means that having a member variable, you’re not constrained to store the information for later use. Doing so cost (a small amount of) memory. It might be possible that cache misses are more frequent, stalling the CPU if it can’t execute out of order.

But in all seriousness, it feels like the question is slightly misplaced. If the information has to persist between method calls, what choice do you have? Besides, is this really your performance bottleneck in your program? Is it slower than comparing a short string? Is it slower than the function call in the first place? If you are genuinely interested in seeing performance comparisons, write a performance test! Create a million instances and measure how long it takes to execute both setups. Then, modify the code so it does something meaningful (i.e. has some actual calculations in the method) and see how much of a bump (or lack thereof) you get.

I’d totally place the variable where it makes logical sense, first. Once I know I have a performance issue, I’ll start attacking my code after I know which are the top offenders. If the pathfinding code is 50000 times slower than the code we discussed above, I won’t spend ages debating about “should it be local or member to make it go faster?”. I wouldn’t even spend a second thinking about that code, if it’s pathfinding that takes most of the time. Sure, then I could think about “moving a local to a member or vice versa” in pathfinding, but in all seriousness, I think it will do next to nothing.

Finally; please don’t just buy what I say as hard facts. Either go out there and read other articles/litterature to strengthen or weaken your assumptions or perform some tests yourself to see what practical, measurable, noticable effect you’ll get. Also, I may be wrong like everyone else. I don’t want to send you off misinformed because I made an error somewhere. I can reason as to why given what I know, but I don’t claim to know everything and I can’t claim that everything I’ve read from other users necessarily are hard facts (even though I often assume they are, especially in my younger years).

I should preface this by saying I really only know C#.Nets implementation, but I assume Mono/Unity follows the same concepts.

Some people say that primitive variables like ints and floats are stored in the stack and will live for the entire program execution

I don’t believe that’s true, value types (like ints and floats) are only sometimes on the stack, it depends on context, what operations are being performed, what is using it, and on the jitter itself.

Your example:

     float x;
     Update () { x = 1.0f; }

Will cause float x to be stored in the classes instance memory, which is on the heap. It is still a value type though, even though it’s existing in the heap.

Your Second Example:

 Update () {float x = 1.0f;}

Will probably be allocated to the stack as it is a local variable, but that doesn’t mean it won’t cross over to the heap.

The Garbage Collector is invoked for the heap only, it has no affect on the running of the stack (but it does use the stack to figure out what is currently referenced and what is not, so that objects are not collected while still being used). It doesn’t really make sense for it to GC the stack as that will always know when values are out of scope due to it’s structure (values at the top will always be discarded first and values at the bottom will be discarded last, hence the name ‘stack’).

So to answer your question directly, Method 2 ‘maybe’ faster but it’s up to what you are using the variable for, do you need it again for something outside that methods scope? if not then declare it as a local variable, need to use it else where? declare it as a member.

Very interesting discussion and good reading for the weekend. I cannot actually add anything of interest since I’m new both in C# and Unity, but I really appreciate all the answers here.

However, I’d like to quote Eric Lippert (I don’t really know how much of an authority he is) on his entry:

“in the Microsoft implementation of C#
on the desktop CLR, value types are
stored on the stack when the value is
a local variable or temporary that is
not a closed-over local variable of a
lambda or anonymous method, and the
method body is not an iterator block,
and the jitter chooses to not
enregister the value.”

So, it’s seem that local value types in general are stored on the stack. This means that they are probably cached and would be more efficient in terms of speed. But again, there is not a definitive answer and not only depends on how stacks and heaps work, but also in your programming needs and design.