If you think about it, an application is made up of two things: the code itself, and the data that stores the state of the application during execution. When a .NET application runs, three main sections of memory (heaps) are created to be used for storage:
• the Code Heap stores the actual native code instructions after they have been Just in Time compiled (JITed)
• the Small Object Heap (SOH) stores allocated objects that are less than 85 K in size.
• the Large Object Heap (LOH) stores allocated objects greater than 85 K.
Everything on a heap has an address, and these addresses are used to track program execution and application state changes.
Applications are usually written to encapsulate code into methods and classes, so .NET has to keep track of chains of method calls as well as the data state held within each of those method calls. When a method is called, it has its own cocooned environment where any data variables it creates exist only for the lifetime of the call. A method can also get data from global/static objects, and from the parameters passed to it.
To keep track of everything (and there is often quite a lot of “everything”) .NET maintains a stack data structure, which it uses to track the state of an execution thread and all the method calls made.
So the stack is used to keep track of a method’s data from every other method call. When a method is called, .NET creates a container (a stack frame) that contains all of the data necessary to complete the call, including parameters, locally declared variables and the address of the line of code to execute after the method finishes. For every method call made in a call tree (i.e. one method that calls another, which calls another, and so on) stack containers are stacked on top of each other. When a method completes, its container is removed from the top of the stack and the execution returns to the next line of code within the calling method (with its own stack frame). The frame at the top of the stack is always the one used by the current executing method.
the stack can store variables that are the primitive data types defined by .NET :
• Byte • SByte • Int16
• Int32 • Int64 • UInt16
• UInt32 • UInt64 • Single
• Double • Boolean • Char
• Decimal • IntPtr • UIntPtr
On the other hand, instances of everything you have defined, including:
• instances of “object”
… are all referred to as “reference types,” and are stored on the heap (the SOH or LOH, depending on their size).