A value type is "allocated" where it is defined.
What that means depends on where you define it:
- In a class/struct, as a field in that struct, enlarging the class/struct in memory to fit the value type value in there
- As a local variable in a method, on the stack, or as a register, or as a field in a generated class (when using "closures"), depending on optimizations
- As a parameter to a method, on the stack or as a register, depending on optimizations
A reference type is sort of a dual value. A reference type is at heart a pointer, and the pointer value follows the same rules for "allocation" as a value type, but once you store a value in it, ie. a reference to an object, that object is on the heap somewhere else.
In other words, the reference variable itself is "allocated" as a value type, but the object it refers to is on the heap.
When you construct an object from a class, space is allocated on the heap to fit all the fields of that class + some overhead in that space.
I seem to recall Jon Skeet having an article about the subject, I'm sure he'll jump in with an answer really soon so stay tuned.