0

"Value types are stack allocated, whereas reference types live on the managed heap."

If I have a local variable (like int a=2;) within a method of a class, where is it allocated?

In our example, a value type is contained within a reference type. Since the reference lives in the managed heap, I am assuming the value type here (int a) is also in the managed heap and not the stack.

Am I missing something here?

Deepanjan Nag
  • 901
  • 3
  • 14
  • 26
  • 1
    Value types are embedded into the containing storage. That can be the stack, but can be other storage too. – CodesInChaos Jul 21 '12 at 19:03
  • http://stackoverflow.com/questions/2565331/fields-of-class-are-they-stored-in-the-stack-or-heap – Oded Jul 21 '12 at 19:05
  • @Oded that question is specifically "fields of a class"; this question is "local method variables in a class method"; very different – Marc Gravell Jul 21 '12 at 19:17
  • @MarcGravell - True. I was really trying to give a reference to the first line of the question - that quote which is oh so very misleading. – Oded Jul 21 '12 at 19:18
  • Ah right, yes, with you now. I do loathe that quote. I always expect it to be adjacent to "structs are for when you don't need methods" – Marc Gravell Jul 21 '12 at 19:19
  • This quote was from the book "C# 4 Unleashed" by Bart De Smet. It's generally a great book, but this statement had me thinking. – Deepanjan Nag Jul 21 '12 at 19:27
  • @DeepanjanNag it would have me thinking the book is very ... misleading – Marc Gravell Jul 21 '12 at 19:31

2 Answers2

3

It is primarily the JIT compiler that determines where local variables are stored. It is a heavy architecture implementation detail, let's limit it to the x86 jitter. Common choices it makes:

  • nowhere. Which will happen with the very simple example you gave, the jitter optimizer can see that a local variable is initialized but not used anywhere and will eliminate it.

  • in a CPU register. That's a very important optimization, no storage location is faster. A variable will almost always live inside a register at least part of the time when the method body executes, necessary because a lot of cpu instructions require the operand to be present in a register first. The jitter will only spill the variable to the stack frame if it runs out of registers (x86 doesn't have many) and needs to re-use a register for another operation

  • in the stack frame for the method. The traditional way everybody thinks about it. A variable is stored at a fixed offset from the EBP register. Accessing those variables is very fast, not quite as fast as when they are stored in a register.

I however also have to talk about ways that the compiler affects the storage location for variable that has local scope in the language (thanks Marc):

  • on the garbage collected heap. This is done by the compiler when it rewrites the code to implement an iterator, captures variables for anonymous methods or lambda expressions or implements methods marked with the async keyword. The local variables become fields of a hidden class that gets allocated on the heap as normal.

  • in the loader heap. Outlandish to a C# programmer but supported by the VB.NET compiler with the Static keyword. A feature that's implemented by the compiler, it acts like a C# static field but with the scope limited to the method body. With lots of auto-generated code to ensure it is initialized correctly, even when called from threads.

Which covers almost all possible storage locations for a variable :) Although I have trouble coming up with a [ThreadStatic] example. This is a possible case of information overload, focus on bullets 2 and 3 for the most common ways. And certainly bullet 3 to think productively about the way managed code works.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Some very valid points; I've added a clarification to my post that it only addresses what happens in IL, i.e. pre-JIT. – Marc Gravell Jul 21 '12 at 19:43
2

Firstly, it should be noted that the first line of your post is misleading, incomplete and inaccurate. Value-types can be pretty much anywhere.

In our example, a value type is contained within a reference type.

the "contained within" here is misleading. The "contained within" you are conflating this with is "instance fields". This does not apply to method local variables. Method local variables, as an implementation detail, live on the stack... except for when they don't! Which includes iterator blocks and captured variables. Since you haven't mentioned either of those things, the answer is probably "on the stack".

I should also note that even for method local variables that are reference types, the variable (i.e. the reference, not the object) still lives on the stack (except for when it doesn't, exactly the same rules).

Note in the above that I'm limiting the discussion to what happens in IL terms, i.e. what the C# compiler does. Hans is quite correct to say that the JIT may do whatever it wants with the IL when it sees it.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900