I understand(not completely why, though) that instances of primitive types such as int, float are stored on the stack and are not heap allocated. But I am a bit confused about how arrays of primitive types are stored and accessed. I have this question because System.Array is a reference type. And reference types are heap allocated.
int[] integers = {1,2,3,4,5};
How are these individual integers stored and accessed on the memory?
Your "understanding" is flawed, basically. Value type values are sometimes stored on the stack - but not when part of an array or any other heap-based object. It's unfortunate that some people choose to make such a blanket statement around value types living on the stack, which then confuses others :(
Besides, the stack/heap distinction is an implementation detail...
See my article on memory for some more details, but definitely read Eric Lippert's blog post (linked in the previous paragraph) for more philosophical considerations. (Read his other posts on value types for even more information.)
You have discovered the reason why the statement "value types are always stored on the stack" is obviously wrong. The truth is that the type of the object being stored is irrelevant to where it is stored. The correct rule is that values with short lifetimes are stored in storage from the short-term "stack" and values with long lifetimes are stored in storage from the long-term "heap".
When you put it that way, it is practically a tautology. Obviously short-lived stuff is allocated from the short-term store, and long-lived stuff is allocated from the long-lived store! How could it be otherwise? But when you put it that way, clearly the type is irrelevant except insofar as the type gives you a hint about the lifetime.
The contents of an array of ints is potentially long-lived, so the ints are allocated from the long-term store. The contents of a local variable of type int is typically short-lived, so it is typically allocated from the short-lived store.
Array itself is always a reference type, so it's stored on heap. Elements of an array are stored on heap too, but always in a contiguous block of memory.
This article by Jeffry richter written back in 2002 explains this concept very clearly.
Related
I read the answer to some of the similar questions but my question is little different due to fact that I do not understand a statement written about this in a book.
Because a struct is a value type, each instance does not require
instantiation of an object on the heap; this incurs a useful savings
when creating many instances of a type. For instance, creating an
array of value type requires only a single heap allocation.
I mean How can array require only a single heap allocation?... or what does it mean by single heap allocation
How can array require only a single heap allocation?... or what does it mean by single heap allocation
First of all, let's clarify what we mean by "heap" vs "stack".
Most programming environments today are stack-based. As you run a program, each time you call a method a new entry is pushed onto a special stack provided for your program. This stack entry (or frame) tells the system where to look for the method's executable code, what arguments were passed, and exactly where to return to in the calling code after the method exits. When a method finishes, it's entry is removed (popped) from the stack, so the program can go back to the previous method. When the stack is empty, the program has finished.1 There is often support for this special stack directly in the CPU.
The memory for the stack is allocated when the program is first launched, which means the stack itself has a fixed (limited) size. This is where "Stack Overflows" come from; get too deep down too many method calls, and the stack will run out of space. Each frame on the stack also has a certain amount of space for local variables for the method, and this is the memory we're talking about when we say value types live on the stack. The local variables stored on the stack do not require new allocations; the memory is already there. Just remember: this only applies in the context of local variables in a method.
The heap, on the other hand, is memory not automatically granted to the program. It is memory the program must request above and beyond it's core allocation. Heap memory has to be managed more carefully (so it doesn't leak — but we have a garbage collector to help with this), but there is (usually) much more of it available. Because it has to be granted by the operating system on request, initial allocations for the heap are also a little slower than memory used from the stack.2 For reference types, you can think of the new keyword as requesting a new heap memory allocation.
As a broad generalization, we say reference types are allocated on the heap, and value types are allocated on the stack (though there are plenty of exceptions for this3).
Now we understand this much, we can start to look at how .Net handles arrays.
The core array type itself is a reference type. What I mean is, for any given type T, the T may (or may not) be a value type, but an array of T (T[]) is always a reference type. In the "stack vs heap" context, this means creating a new array is a heap allocation, even if T is a value type. Arrays in .Net also have a fixed size4.
An additional attribute of value types is they also have a known/fixed size, based on the members. Therefore, an array of value types has a fixed number of elements, each with a known fixed size. That's enough information so allocating a new array of value types will get all the space for the array object and it's elements in single heap allocation. The value of each item (not just a reference) is held right there with the array's core memory. Now we have a bunch of value-type objects, but their memory is on the heap, rather than the stack.
This can be further complicated by a value type with one or more reference type members. In this situation, the space for the value type is allocated as normal, but the the part of the value for the reference members is just a reference. It still requires separate allocations or assignments to populate those reference members.
For an array holding reference types, the initial heap allocation for the array still allocates space for all the elements, but space reserved for each element is only enough for the reference. That is, initially each element in the array is still null. To populate the array you must still set those references to objects in memory, either by assigning existing objects or allocating new ones.
Finally, just as we were able to use arrays to get a value-type onto the heap, instead of the stack, there are also ways to force reference types to allocate from the stack. However, generally you should not do this unless you really understand the full implications.
1) There are different conventions on exactly when a frame is pushed/popped for each method call, depending on the platform, compiler configuration, and more, so only look at this paragraph for the general idea; the exact specifics will be incorrect in some particulars on any given platform.
2) For future reading, it is also useful to understand how programs handle addressing for heap memory.
3) Eric Lippert has an excellent write-up of this topic.
4) That is, arrays in .Net they are true arrays in the full formal computer science sense, unlike the associative array-like collection types in many other platforms. .Net has these, too, but it calls them what they are: collections rather than arrays.
An array is itself a reference type, which means, it is allocated on the managed heap. But if it is an array of a value type, it reserves the the memory needed for its size in one single step. Lets you have a struct with 4 Int32 in it.
A struct4Int[1000] will allocate 16000 bytes in one step.
An array of a reference type will take only the memory needed for the referencing (32bit or 64bit per item, depending on the architecture you are compiling for). Lets say a class with 4Int32 in it.
A class4Int[1000] will allocate 4000 or 8000 bytes at first.
The items are filled with the address of the references, which is intially null.
After creating the array you will have to allocate memory for every instance of the reference type and putting it's reference into the array (multiple allocations on the heap), adding another 16000 bytes on the heap in 1000 small pieces.
Firstly, I'm currently working in C# and I've been reading up on memory management. So far, I've read through some great answers on stack overflow explaining the difference between stack memory and the managed heap memory. The majority of the answers state that by declaring:
int x = 5, you're allocating enough memory for the type of x within the stack memory.
I understand how this works as well as the scope of it, however when I read the explanation of heap memory, it confused me.
If you're saying int x = 5, since int is an alias of System.Int32, wouldn't x technically be a pointer to a new instance of the System.Int32 struct? And if so, wouldn't it then be stored in the heap memory since that's used for instance objects.
In this tutorial, it states (for the line class1 cls1 = new class1()):
... creates a pointer on the stack and the actual object is stored in a different type of memory location called ‘Heap’.By this logic, isn't everything stored on the heap and only pointers stored on the stack? Examples being new instances of System.String, System.Int64, System.Boolean, System.Decimal etc.
I thought I understood it, however clearly I don't, so I would appreciate someone explaining whether the stack is only for pointers or which part I've misinterpreted. Thanks in advance.
You can use the following rule: if it's a struct (including primitive types) then it's allocated where it's declared, otherwise a pointer to an object in heap is allocated.
Possible locations are:
For local variables it's a stack. Note that physically values can be stored in CPU registers rather than in stack.
For class fields it's inside of contiguous chunk of memory allocated in heap for an instance of the class.
For static fields it's allocated in loader heap as a part of type metadata (сorrect me if I am wrong).
Warning: this is just basic, non-comprehensive explanation to have a basic understanding of what's going on. The reality is more complicated. Local variables can be hoisted and moved to heap, optimizer can eliminate them altogether, etc...
You may want to check Classes and structs (MSDN) to understand what is stored where and how:
int x = 1; // 32 bits holding an integer in the stack
System.Object bo = x; // 32+some more bits are on the heap to hold the "boxed" (wrapped to be kept on the heap) integer value
System.Object ho = new Object(); // some bits are created on the heap right from the start
In simple words there are two types of objects: classes and structs. The classes (reference types) are meant to be stored on the heap and have a pointer to them while structs are meant to be stored in the stack (the structs can be relocated to the heap though with a little overhead of wrapping("boxing") them).
If you really need/want to understand how CLR works in general, consider reading "CLR via C#" (Richter).
As objects are reference types they are stored in the heap and primitive data types are store on the stack.
But an object is a collection of primitive datatypes as well reference type i.e. a object may have a integer data member and/or may have another object within it.
When the scope ends the primitive data memory is released from the stack but the heap memory is handled by the garbage collector.
Now my question is: if an object also has a primitive data member then when are they removed?
As objects are reference types they are stored in the heap and primitive data types are store on the stack.
Not quite. Value types, which includes the primitives, but also struct types are stored on the stack when they are locals. They can also be stored on the heap if boxed or in an array or, as you note, a field of a reference type.
Reference types have one or more references which might also be stored on the stack—the local(s) you address it through—and the representation of the object itself on the heap.
When the scope ends the primitive data memory is released from the stack but the heap memory is handled by the garbage collector.
Not quite.
First, there isn't really a "releasing" operation. Say we were using 4 slots on the stack to store the values 1-4*:
[1][2][3][4][ ][ ][ ][ ]
^
Using up to here.
(I'm going to completely ignore the matter of what happens between function calls for the sake of simplicity).
Now say we stop using the last 2 slots. There's no need to "release" anything:
[1][2][3][4][ ][ ][ ][ ]
^
Using up to here.
Only if we go to, e.g. use 1 new slot to store the value 5, need we overwrite anything:
[1][2][5][4][ ][ ][ ][ ]
^
Using up to here.
The "releasing" just changed which memory was considered in use and which considered available.
Now consider the following C# code:
public void WriteOneMore(int num)
{
int result = num + 1;
Console.WriteLine(result);
}
Say you call that with the value 42. The relevant portion of the stack is:
[42]
^
Using up to here.
Now, after int result = num + 1; there are two values in scope; result and num. As such the stack might be:
[42][43]
^
Using up to here.
However, num is never used again. The compiler and jitter know this, so they might have reused the same slot:
[43]
^
Using up to here.
Because "in scope" refers to the source code, and what variables can be used in particular places, but the stack is used according to what variables actually are used in particular places, so it can often use less stack space than the source may suggest. Conversely, sometimes you find the same variable becoming more than one slot, if it makes things easier for the compiler in some way. This is no big deal here, but becomes important when we come to reference types.
the heap memory is handled by the garbage collector.
Let's consider what that actually means.
If an application needs heap memory for new objects, it takes that memory from a free part of a heap. If there isn't enough heap memory available it could ask the OS for more, but before that it may try garbage collecting.
When this happens, first the garbage collector makes a note of what heap-stored (reference types including boxed value types) objects it can't get rid of.
One set of such objects are those that are in a static variable.
Another is those that are in reachable parts of the stack. So if the stack is like:
["a"]["b"]["c"]["d"]["e"]
^
Using up to here.
Then the values "a", "b" and "c" cannot be collected.
The next set is any object that can be reached via a field of one of the objects that it already knows can't be collected, or through a field in one of those, and so on.
(A final step is any object that isn't ineligible due to the above, which needs to be finalised, they get put on the finalisation queue here, so they'll be eligible after the finaliser thread has dealt with them).
Now. On the heap, the object looks a bit like;
[Sync][RTTI][Field0][Field1] … [FieldN]
Here "Sync" marks the sync block used if you lock on the object. "RTTI" marks a pointer to type information, used to obtain the type and to enable virtual methods to work. The rest is fields, whether value-types contained directly or references to other reference types.
Okay. Let's say this object is one that the collector decides it can collect.
It simply changes that block of memory from being considered not available to use, to being available to use. That's it.
In a subsequent step all in-use objects get moved together to compact the used memory into one block and the free into another. Our old object might be overwritten at this point, or it might not be overwritten for some time to come. We don't really care, because the corpse of that dead object is just a bunch of 1s and 0s sitting there doing nothing now, waiting for the palimpsest of volatile memory to be written to once more.
So the primitive fields are released at the point where the object's memory is considered available to use, but again, they may still be present in RAM for some time, or not, they're just ignored.
It's worth remembering, that just as the values on the stack may not correspond to what is "in scope" in the source code, so therefore an object can be collected while it's in scope; garbage collection depends on the real use of the stack, not the source. This mostly doesn't affect anything, because most attempts to use something in the code means that it is now part of the real use of the stack and therefore won't be collected. Of the very few cases where it can affect something probably the most common is an attempt to use a Timer that is only referenced through a local; the main thread doesn't use it any more so that stack space can be used up and then the timing thread finds no such timer. This is where GC.KeepAlive() comes in.
*When it comes to the running code, locals might be stored in registers and never actually in the stack of memory. At the level of considering how the .NET code works, it's generally easiest just to consider them also "on the stack". At the level of considering how the machine code works, that's not true. When the garbage collector looks at what is "on the stack" to see what it can't delete, it also looks at what references are in registers.
It is very hard to explain such a fundamental but not always easy to understand things. However in the last 15 years many good explanation was written.
In case you do not want to read them (obviously...) here is a very short and (consequently not complete) wrap up: (note: still I strongly recommend to investigate toward in the literature)
Note: The following part is edited slightly based on comment conversation about "primitive type" terminology:
(edit)
In this question's context it is more appropriate to talk about "value type" instead of "primitive type". Regardless of the type is primitive or not, it only matters is it value type or reference type in this context.
(end edit)
Now the point:
Reference type have a reference (anywhere, like in heap or stack) which points the instance allocated always on the heap. Value type are stored (anywhere, like in the heap or stack) immediately embedded that place, so there is no indirection.
Samples:
Local variable of a value type: stack
Local variable of a reference type: instance itself on the heap, and the reference is on the stack
Member variable (value type): Embedded into the allocated space of the instance which's member variable it is.
Member variable (reference type): Its reference embedded into the allocated space of the instance which's member variable it is, and its instance on the heap.
Now my question is: if an object also has a primitive data member then when are they removed?
Answer: When the containing object is removed. (Hopefully it is clear based on the 4 samples: The containing object can be on the heap or on the stack, so the "containing object removal" could be a GC collection or a simple stack pointer set when returning from a method.)
My understanding has always been, regardless of C++ or C# or Java, that when we use the new keyword to create an object it allocates memory on the heap. I thought that new is only needed for reference types (classes), and that primitive types (int, bool, float, etc.) never use new and always go on the stack (except when they're a member variable of a class that gets instantiated with new). However, I have been reading information that makes me doubt this long standing assumption, at least for Java and C#.
For example, I just noticed that in C# the new operator can be used to initialize a value type, see here. Is this an exception to the rule, a helper feature of the language, and if so, what other exceptions would there be?
Can someone please clarify this?
I thought that new is only needed for reference types (classes), and that primitive types (int, bool, float, etc.) never use new
In C++, you can allocate primitive types on the heap if you want to:
int* p = new int(42);
This is useful if you want a shared counter, for example in the implementation of shared_ptr<T>.
Also, you are not forced to use new with classes in C++:
void function()
{
MyClass myObject(1, 2, 3);
}
This will allocate myObject on the stack. Note that new is rarely used in modern C++.
Furthermore, you can overload operator new (either globally or class-specific) in C++, so even if you say new MyClass, the object does not necessarily get allocated on the heap.
I don't know precisely about Java (and it seems quite difficult to get a documentation about it).
In C#, new invokes the constructor and returns a fresh object. If it is of value type, it is allocated on the stack (eg. local variable) or on the heap (eg. boxed object, member of a reference type object). If it is of reference type, it always goes on the heap and is managed by the garbage collector. See http://msdn.microsoft.com/en-us/library/fa0ab757(v=vs.80).aspx for more details.
In C++, a "new expression" returns a pointer to an object with dynamic storage duration (ie. that you must destroy yourself). There is no mention of heap (with this meaning) in the C++ standard, and the mechanism through which such an object is obtained is implementation defined.
My understanding has always been, regardless of C++ or C# or Java, that when we use the new keyword to create an object it allocates memory on the heap.
Your understanding has been incorrect:
new may work differently in different programming languages, even when these languages are superficially alike. Don't let the similar syntax of C#, C++, and Java mislead you!
The terms "heap" and "stack" (as they are understood in the context of internal memory management) are simply not relevant to all programming languages. Arguably, these two concepts are more often implementation details than that they are part of a programming language's official specification.
(IIRC, this is true for at least C# and C++. I don't know about Java.)
The fact that they are such widespread implementation details doesn't imply that you should rely on that distinction, nor that you should even know about it! (However, I admit that I usually find it beneficial to know "how things work" internally.)
I would suggest that you stop worrying too much about these concepts. The important thing that you need to get right is to understand a language's semantics; e.g., for C# or any other .NET language, the difference in reference and value type semantics.
Example: What the C# specification says about operator new:
Note how the following part of the C# specification published by ECMA (4th edition) does not mention any "stack" or "heap":
14.5.10 The new operator
The new operator is used to create new instances of types. […]
The new operator implies creation of an instance of a type, but does not necessarily imply dynamic allocation of memory. In particular, instances of value types require no additional memory beyond the variables in which they reside, and no dynamic allocations occur when new is used to create instances of value types.
Instead, it talks of "dynamic allocation of memory", but that is not the same thing: You could dynamically allocate memory on a stack, on the heap, or anywhere else (e.g. on a hard disk drive) for that matter.
What it does say, however, is that instances of value types are stored in-place, which is exactly what value type semantics are all about: Value type instances get copied during an assignment, while reference type instances are referenced / "aliased". That is the important thing to understand, not the "heap" or the "stack"!
In c#, a class always lives on the heap. A struct can be either on the heap or stack:
variables (except captures and iterator blocks), and fields on a struct that is itself on the stack live on the stack
captures, iterator blocks, fields of something that is on the heap, and values in an array live on the heap, as do "boxed" values
Java 7 does escape analysis to determine if an object can be allocated on the stack, according to http://download.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html.
However, you cannot instruct the runtime to allocate an object on heap or on stack. It's done automatically.
Regarding c#, read The Truth About Value Types.
You will see that value types can go on the heap as well.
And at this question is suggested that reference types could go on the stack. (but it does not happen at the moment)
(Referring to Java) What you said is correct- primitives are allocated on the stack (there are exceptions e.g. closures). However, you might be referring to objects such as:
Integer n = new Integer(2);
This refers to an Integer object, and not a primitive int. Perhaps this was your source of confusion? In this case, n will be allocated on the heap. Perhaps your confusion was due to autoboxing rules? Also see this question for more details on autoboxing. Check out comments on this answer for exceptions to the rule where primitives are allocated on the heap.
In Java and C#, we don't need to allocate primitive types on the heap. They can be allocated on the stack ( not that they are restricted to stack ). Whereas, in C++ we can have primitive as well as user defined types to be allocated on both stack and heap.
In C++, there's an additional way to use the new operator, and that's via 'placement new'. The memory you point it to could exist anywhere.
See What uses are there for "placement new"?
I know that one of the differences between classes and structs is that struct instances get stored on stack and class instances(objects) are stored on the heap.
Since classes and structs are very similar. Does anybody know the difference for this particular distinction?
(edited to cover points in comments)
To emphasise: there are differences and similarities between value-types and reference-types, but those differences have nothing to do with stack vs heap, and everything to do with copy-semantics vs reference-semantics. In particular, if we do:
Foo first = new Foo { Bar = 123 };
Foo second = first;
Then are "first" and "second" talking about the same copy of Foo? or different copies? It just so happens that the stack is a convenient and efficient way of handling value-types as variables. But that is an implementation detail.
(end edit)
Re the whole "value types go on the stack" thing... - value types don't always go on the stack;
if they are fields on a class
if they are boxed
if they are "captured variables"
if they are in an iterator block
then they go on the heap (the last two are actually just exotic examples of the first)
i.e.
class Foo {
int i; // on the heap
}
static void Foo() {
int i = 0; // on the heap due to capture
// ...
Action act = delegate {Console.WriteLine(i);};
}
static IEnumerable<int> Foo() {
int i = 0; // on the heap to do iterator block
//
yield return i;
}
Additionally, Eric Lippert (as already noted) has an excellent blog entry on this subject
It's useful in practice to be able to allocate memory on the stack for some purposes, since those allocations are very fast.
However, it's worth noting that there's no fundamental guarantee that all structs will be placed on the stack. Eric Lippert recently wrote an interesting blog entry on this topic.
Every process has a data block consists of two different allocatable memory segment. These are stack and heap. Stack is mostly serving as the program flow manager and saves local variables, parameters and returning pointers (in a case of returning from the current working function).
Classes are very complex and mostly very large types compared to value types like structs (or basic types -- ints, chars, etc.) Since stack allocation should be specialized on the efficiency of program flow, it is not serving an optimal environment to keep large objects.
Therefore, to greet both of the expectations, this seperated architecture came along.
How the compiler and run-time environment handle memory management has grown up over a long period of time. The stack memory v.s. heap memory allocation decision had a lot to do with what could be known at compile-time and what could be known at runtime. This was before managed run times.
In general, the compiler has very good control of what's on the stack, it gets to decide what is cleaned up and when based on calling conventions. The heap on the other hand, was more like the wild west. The compiler did not have good control of when things came and went. By placing function arguments on the stack, the compiler is able to make a scope -- that scope can be controlled over the lifetime of the call. This is a natural place to put value types, because they are easy to control as opposed to reference types that can hand out memory locations (pointers) to just about anyone they want.
Modern memory management changes a lot of this. The .NET runtime can take control of reference types and the managed heap through complex garbage collection and memory management algorithms. This is also a very, very deep subject.
I recommend you check out some texts on compilers -- I grew up on Aho, so I recommend that. You can also learn a lot about the subject by reading Gosling.
In some languages, like C++, objects are also value types.
To find an example for the opposite is harder, but under classic Pascal union structs could only be instantiated on the heap. (normal structs could be static)
In short: this situation is a choice, not a hard law. Since C# (and Java before it) lack procedural underpinnings, one can ask themselves why it needs structures at all.
The reason it is there, is probably a combination of needing it for external interfaces and to have a performant and tight complex (container-) type. One that is faster than class. And then it is better to make it a value type.
Marc Gravell already explained wonderfully the difference regarding how value and reference types are copied which is the main differentiation between them.
As to why value types are usually created on the stack, that's because the way they are copied allows it. The stack has some definite advantages over the heap in terms of performance, particularly because the compiler can calculate the exact position of a variable created in a certain block of code, which makes access faster.
When you create a reference type you receive a reference to the actual object which exists in the heap. There is a small level of indirection whenever you interact with the object itself. These reference types cannot be created on the stack because the lifetime of values in the stack is determined, in great part, by the structure of your code. The function frame of a method call will be popped off the stack when the function returns, for example.
With value types, however, their copy semantics allows the compiler, depending on where it was created, to place it in the stack. If you create a local variable that holds an instance of a struct in a method and then return it, a copy of it will be created, as Marc explained above. This means that the value can be safely placed in the stack, since the lifetime of the actual instance is tied to the method's function frame. Anytime you send it somewhere outside the current function a copy of it will be created, so it doesn't matter if you tie the existence of the original instance to the scope of the function. Along these lines, you can also see why value types that are captured by closures need to go in the heap: They outlive their scope because they must also be accessible from within the closure, which can be passed around freely.
If it were a reference type, then you wouldn't be returning a copy of the object, but rather a reference, which means the actual value must be stored somewhere else, otherwise, if you returned the reference and the object's lifetime was tied to the scope in which it was created, it would end up pointing to an empty space in memory.
The distinction isn't really that "Value types go on the stack, reference types on the heap". The real point is that it's usually more efficient to access objects that live in the stack, so the compiler will try and place those values it can there. It simply turns out that value types, because of their copy semantics, fit the bill better than reference types.
I believe that whether or not to use stack or heap space is the main distinction between the two, perhaps this article will shed some light on your question: Csharp classes vs structs
The main difference being that the heap may hold objects that live forever while something on the stack is temporary in that it will disappear when the enclosing callsite is exited. This is because when one enters a method it grows to hold local variables as well as the caller method. When the method exits (ab)normally eg return or because of exception each frame must be popped off the stack. Eventually the interested frame is popped and everything on it lost.
The whole point about using the stack is that it automatically implements and honours scope. A variable stored on the stack exists until the functiont that created it exits and that functions stack frame is popped. Things that have local scope are natural for stack storage things that have bigger scope are more difficult to manage on the stack. Objects on the heap can have lifetimes that are controlled in more complex ways.
Compilers always use the stack for variables - value or reference it makes little difference. A reference variable doesn't have to have its value stored on the stack - it can be anywhere and the heap makes a more efficient if the object referenced is big and if there are multiple references to it. The point is that the scope of a reference variable isn't the same as the lifetime of the object it references i.e. a variable may be destroyed by being popped off the stack but the object (on the heap) it references might live on.
If a value type is small enough you might as well store it on the stack in place of a reference to it on the heap - its lifetime is tied to the scope of the variable. If the value type is part of a larger reference type then it too could have multiple references to it and hence it is more natural to store it on the heap and dissociate its lifetime from any single reference variable.
Stack and heap are about lifetimes and the value v reference semantics is almost a by product.
Have a look at Value and Reference
Value types go on the stack, reference types go on the heap. A struct is a value type.
There is no guaruantee about this in the specification though, so it might change in future releases:)