public class MyClass
    public int Age;
    public int ID;

public void MyMethod() 
    MyClass m = new MyClass();
    int newID;

To my understanding, the following is true:

  1. The reference m lives on the stack and goes out of scope when MyMethod() exits.
  2. The value type newID lives on the stack and goes out of scope when MyMethod() exits.
  3. The object created by the new operator lives in the heap and becomes reclaimable by the GC when MyMethod() exits, assuming no other reference to the object exists.

Here is my question:

  1. Do value types within objects live on the stack or the heap?
  2. Is boxing/unboxing value types in an object a concern?
  3. Are there any detailed, yet understandable, resources on this topic?

Logically, I'd think value types inside classes would be in the heap, but I'm not sure if they have to be boxed to get there.


Suggested reading for this topic:

  1. CLR Via C# by Jeffrey Richter
  2. Essential .NET by Don Box

All value types exist on the stack. Objects exist on the heap.

There's a good (basic) explanation of this at this web site:

Boxing/unboxing of value types is actually somewhat expensive. When Value types are boxed as an Object, they become reference types that are placed on the heap. When unboxed they are moved back to the stack.


Dan Herbert
+1  A: 
  1. Any references or value types that an object own live in the heap.
  2. Only if you're casting ints to Objects.
+1  A: 

The best resource I've seen for this is the book CLR via C# by Jeffrey Richter. It's well worth reading if you do any .NET development. Based on that text, my understanding is that the value types within a reference type do live in the heap embedded in the parent object. Reference types are always on the heap. Boxing and unboxing are not symmetric. Boxing can be a bigger concern than unboxing. Boxing will require copying the contents of the value type from the stack to the heap. Depending on how frequently this happens to you there may be no point in having a struct instead of a class. If you have some performance critical code and you're not sure if boxing and unboxing is happening use a tool to examine the IL code of your method. You'll see the words box and unbox in the IL. Personally, I would measure the performance of my code and only then see if this is a candidate for worry. In your case I don't think this will be such a critical issue. You are not going to have to copy from the stack to the heap (box) every time you access this value type inside the reference type. That scenario is where boxing becomes a more meaningful problem.


Do value types within objects live on the stack or the heap?

On the heap. They are part of the allocation of the footprint of the object, just like the pointers to hold references would be.

Is boxing/unboxing value types in an object a concern?

There's no boxing here.

Are there any detailed, yet understandable, resources on this topic?

+1 vote for Richter's book.

Brad Wilson
+5  A: 

Value-type values have to live together with the object instance in the managed heap. The thread's stack for a method only lives for the duration of a method; how can the value persist if it only exists within that stack?

A class' object size in the managed heap is the sum of its value-type fields, reference-type pointers, and additional CLR overhead variables like the Sync block index. When one assigns a value to an object's value-type field, the CLR copies the value to the space allocated within the object for that particluar field.

Take for example, a simple class with a single field.

public class EmbeddedValues
  public int NumberField;

And with it, a simple testing class.

public class EmbeddedTest
  public void TestEmbeddedValues()
    EmbeddedValues valueContainer = new EmbeddedValues();

    valueContainer.NumberField = 20;
    int publicField = valueContainer.NumberField;

If you use the MSIL Disassembler provided by the .NET Framework SDK to peek at the IL code for EmbeddedTest.TestEmbeddedValues()

.method public hidebysig instance void  TestEmbeddedValues() cil managed
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] class soapextensions.EmbeddedValues valueContainer,
           [1] int32 publicField)
  IL_0000:  nop
  IL_0001:  newobj     instance void soapextensions.EmbeddedValues::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   20
  IL_000a:  stfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_000f:  ldloc.0
  IL_0010:  ldfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_0015:  stloc.1
  IL_0016:  ret
} // end of method EmbeddedTest::TestEmbeddedValues

Notice the CLR is being told to stfld the loaded value of "20" in the stack to the loaded EmbeddValues' NumberField field location, directly into the managed heap. Similarly, when retrieving the value, it uses ldfld instruction to directly copy the value out of that managed heap location into the thread stack. No box/unboxing happens with these types of operations.

+1  A: 
  • Ans#1: Heap. Paraphrasing Don Box from his excellent 'Essential .Net Vol 1'

Reference Types(RT) always yield instances that are allocated on the heap. In contrast, value types(VT) are dependent on the context - If a local var is a VT, the CLR allocates memory on the stack. If a field in a class is a member of a VT, then the CLR allocates memory for the instance as part of the layout of the object/Type in which field is declared.

  • Ans#2: No. Boxing would occur only when you access a struct via a Object Reference / Interface Pointer. obInstance.VT_typedfield will not box.

    RT variables contains the address of the object it refers to. 2 RT var can point to the same object. In contrast, VT variables are the instances themselves. 2 VT var cannot point to same object(struct)

  • Ans#3: Don Box's Essential .net / Jeffrey Richter's CLR via C#. I have a copy of the former... though the later may be more updated for .Net revisions