Efficiency when declaring variables
Hi
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?
Answer by Statement · Nov 22, 2015 at 05:27 PM
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).
This topic is something I've been wondering myself. Before Unity my main work was in the virtual world Second Life, which uses a JIT scripting language. In there, tiny changes would have a noticeable effect when running. I never actually did performance testing for it, but I was taught that if a function needed to run often (Update equivalent), all variables used should be member, as any local variables would need to be created and destroyed every cycle and would hurt performance.
Doing a search, I found a thread on the Unity forums from a few years ago on this topic that backs up what @Statement says here, in that it's actually a little faster for basic variables to be local if not needed outside the method.
as any local variables would need to be created and destroyed
I think the keyword here is "created" and "destroyed". If the object living on the stack has a constructor and destructor that does significant amount of work, then you'd have to pay the price of constructing and destructing the object. Consider a constructor of a struct that for some reason access a database to find values based on an ID. Every time the function is called, the constructor would be called and the database would be invoked. This is an implicit query. For performance reasons, the struct might be better off as a cached member variable - if it makes sense in the first place. I don't know how the variable is intended to be used. It's a tradeoff between memory and time in this case.
I did briefly consider adding that into the topic, but since the question mentions primitive types such as ints and floats specifically, I felt there would be no need.
I suggest you look at the generated IL to see what information becomes available for the JIT.
From the top of my head, I think it says how large the stack frame is and then where each primitive is located in the stack. There's no need for complex constructor logic to execute for each int or float - other than initializing the value. "construction" of primitives should just be bumping up the stack pointer n bytes (or bumping down, if you consider the stack being at the top - either way its a simple arithmetic register operation).
This is my understanding. Don't interpret it as "this is exactly what happens". I have looked at some IL code but I haven't debugged JIT generated native code.
Answer by AngryTilde · Nov 22, 2015 at 02:51 PM
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.
but that doesn't mean it won't cross over to the heap.
Could you tell me where I can find more? What's the process of moving stack to heap called?
If you're sure you want to go down that rabbit hole, msdn has an article on the process Boxing and Unboxing the implementation in $$anonymous$$ono might be slightly different.
Eric Lippert also has what I find one of the best blogs about value and reference types and is worth a read not only for that but his views on 'stack vs heap' (Again this is for $$anonymous$$icrosofts Compiler but I think it's a good read regardless).
Edit: Also his blog post The Truth about Value types is really interesting too.
Thanks AngryTilde, I really enjoyed reading the links.
Answer by Cheo · Nov 23, 2015 at 07:52 PM
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.