9

As Value type variable allocates memory in Stack whereas Reference type allocates it in Heap.

So how the memory allocated when a value type variable (e.g. int i = 4;) is declared in the reference type (e.g. in a class).

How the overall memory allocation works in .NET for value type & reference type, and also value type inside the scope of reference type.

Please explain it or provide any links regarding that.

phuclv
  • 37,963
  • 15
  • 156
  • 475
usr021986
  • 3,421
  • 14
  • 53
  • 64

4 Answers4

18

A value type variable allocates memory on the stack whereas a reference type allocates it in heap.

No, that statement is completely wrong. Lots of people believe that, but it is obviously false, as you have discovered.

How is the memory allocated when a value type variable int i = 4; is declared as a field of a reference type?

Clearly you know why your first statement is completely wrong. The integer field of the class cannot be allocated on the stack because the object might live longer than the stack frame.

To understand what is really going on, first you have to realize that there are three kinds of things:

  • value types
  • references
  • instances of reference type

References and instances of reference type are completely different, just as a piece of paper containing my address and my actual house are completely different.

The next thing you have to understand is that there are two kinds of storage: long-term and temporary storage. Long-term storage is usually called "the heap", but I prefer to think of it simply as long-term storage. Temporary storage is usually called "the stack" but that is also misleading because of course there could be multiple stacks, there could be temporaries stored in registers, and so on.

An instance of a reference type occupies memory in the long-term storage. (Sometimes it would be possible to determine that an instance of a reference type is short-lived, and put it in temporary storage, but we do not do this optimization in practice.)

A variable is a storage location which stores either a value of value type or a reference.

Where the storage location of the variable is allocated depends on the lifetime of the variable. If the variable is a local variable known to be of short lifetime, it is allocated from the temporary storage pool. If the variable is known to be of long lifetime (because, say, it is an outer variable of a closure) then it is allocated off the long-term storage pool.

If the variable is a field of a class, we already know that its storage comes from the long-term pool. If the variable is a field of a value type, that value type inhabits storage somewhere; the field inhabits the same storage.

If the variable is an array element, it is allocated off the long-term storage pool; arrays are instances of reference type.

The key to getting your understanding correct is to simply stop believing the myth that whether a variable is of reference or value type affects where the storage is allocated. That is not true and has never been true, and doesn't even make any sense.

The only thing that affects where a variable is stored is how long does the variable live for. Short-lived variables are allocated off the temporary pool -- the stack, or registers -- and long-lived variables are allocated off the long-term storage pool -- the heap.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Hi Eric, Thanks for the explanation. But some points in your answer confused me further more. Can you please explain how we can differentiate between short lived variable & long lived variable. If you have any article or link explaing the detailed fact about the same, please suggest! – usr021986 Sep 09 '11 at 04:11
  • @user373083: You distinguish between short-lived variables and long-lived variables like this: local variables (including temporaries) that are (1) not in an iterator block, and (2) not outer variables of any closure are short-lived variables. Fields of structs are short-lived if the struct is stored in a short-lived variable. All other variables are long-lived. – Eric Lippert Sep 09 '11 at 04:55
  • @user: Remember, you never actually _need_ to use the stack; it's just an optimisation. For a way to write programs that don't use the stack for variables or return addresses, Google Eric's series on Continuation Passing Style. If this sort of style is baked into the JIT, so it generates all methods' code this way, we wouldn't be using stack at all! That would make things like threads a lot cheaper, enable true continuations (which are impractical in the current CLR), etc.. But we wouldn't have a stack, which is quite useful for both debugging and simplicity of the generated code. – configurator Sep 09 '11 at 17:37
  • (continued) My point is: if we implement a CLR & JIT that supports CPS, there would be no stack. And all current CLR programs would still be just as valid. That's why it's only an implementation detail. – configurator Sep 09 '11 at 17:38
  • @configurator: Alternatively, there could be *two* stacks -- one to store local variables, and one to store return addresses. A two-stacks-per-thread approach makes it much easier to write unsafe code that does not fall prey to stack-smashing attacks. Essentially the stack, or CPS, are both ways to implement the concept of *function activation*; there are lots of ways to implement this concept. Using a single stack just happens to be a cheap and easy way to do it, so that's what we use. – Eric Lippert Sep 09 '11 at 17:47
  • Honestly, the main reason I like CPS is it prevents stack overflows when code is correct and yet deeply recursive. Continuations are just an added bonus! – configurator Sep 09 '11 at 17:55
  • @configurator: Indeed, one of the interesting side effects of us adding CPS (in its thin disguise) to C# 5 is that it will make stackless programming much easier. Given how aggressive the CLR is about taking down processes that blow their stack, I wonder if this will encourage people to rewrite recursive-descent programs into CPS programs. (Of course you are just trading one limited resource for another; the continuation of a method that would be deeply recursive is potentially reified as an object that is expensive to garbage collect rather than as a deep stack.) – Eric Lippert Sep 09 '11 at 18:36
  • @Eric: Is there a standrd way that variables are allocated memory for every language or there are differenet types of allocation method ? – usr021986 Sep 13 '11 at 04:23
  • @user373083: Most language have three kinds of storage: temporary, long-lived, and static. C# doesn't draw much of a distinction between the three, unlike, say, C, where it is more important to understand the lifetimes of variables thanks to the ability to persist references to variables by storing pointers beyond the lifetimes of the variables. – Eric Lippert Sep 13 '11 at 06:50
7

This is why Eric Lippert reminds us that the stack is an implementation detail.

When an instance of a value type is a member of a reference type yes, it is stored on the managed heap along with the parent object. It's a good question and something you should understand, just not something that should drive your design in most scenarios.

structs should be small, simple data types that are relatively cheap to create and pass around. Reference types are your complex types, require only a copy of the reference to pass to a method, but of course come with some baggage due to being allocated on the heap. Here is a good follow up post regarding the implications of stack versus heap allocations.

There are plenty of references out there which explain the performance implications of value types versus reference types. You should learn all about it and also understand that, most of the time, it is a semantic decision, not a performance decision.

Austin Arnett
  • 117
  • 1
  • 10
Ed S.
  • 122,712
  • 22
  • 185
  • 265
2

So how the memory allocated when a value type variable(eg int i =4;) is declared in the reference type (eg. in a class).

If the object lies on heap, it means all it's member variable(s) lies there.

Mahesh
  • 34,573
  • 20
  • 89
  • 115
1

here is a nice article.

BTW: not allways goes a Value on the stack - it might end in Heap.

Random Dev
  • 51,810
  • 9
  • 92
  • 119