Stack and heap, both are the most used words to describe if a variable/object is stored in a storage location.
There are 3 storage locations in C# implementation of CLR
- Stack locations
- Heap locations
- Registers
Stack:
All the value types in c# can be stored on the stack. The stack always stores the following:
- Value type variables and method parameters (Includes all the primitive types).
- The reference part of reference typed variables (Includes an object reference).
Example:
As stack incorporates LIFO (Last In First Out) order, when a function is called a unit/block of memory is placed on top of the stack for storing the local variables and do stuff in the method. When the function is done executing the code in the method, the block of memory becomes unused as the block is pops out of stack at the end of curly brace. Stack does this by moving the pointer just a step behind.
The ability to free up its own allocated memory makes stack very special and highly efficient. But if a program uses too much of stack, this can lead to stack overflow exceptions as well.
Heap:
All the reference types in c# are stored on Heap. Unlike stack, heap is another storage location but the objects are not organized to serve you faster.
Example:
When the CLR invokes new keyword on an object, memory for that object is actually created on the heap.
If an object is created on the heap memory, the object is never destroyed until someone free up the memory for that object. This is true for c++ language. A developer has to write code to clean up the unused objects when the program ends on a curly brace. But in C#, a garbage collector is always running as a background thread, which cleans up the unused objects.
In an application lifetime, if the objects are left over without deallocating, then this could cause memory leaks in the application.
Registers:
Not every type in C# is stored on stack and heap all the time. If a variable is a method argument or a local variable, then it can be stored in CPU register. This is because the registers are the fastest way to access the items.
But this is not true for every method argument or local variable. If the value fits in CPU register then it stores into registers otherwise based on the type of the value.
How do these work when multi-threading is used in an application?
In a multi-threaded application, every thread will have its own stack. But the heap is same for all the threads in the application, this makes multi threading possible in C#.
The above snippet is from albahari
The above code snippet
- Shows an example of thread safe code using a static variable done.
- Static variables are stored on heap.
- As stated already in multi-threading application, all the threads share same heap.
- So the variable done is used to achieve locking in multi-threaded applications so that no collision between the threads will happen.
Conclusion:
Memory allocation is upto the memory allocator to decide where to store the objects or the value types.
The basic concept of storing a value type to stack and storing a reference type to heap is pretty common in any programming language but it can vary based on the underlying wires that ties it up.
In a language like C#, where the GC (Garbage Collector) is automated to free up memory, developers don't care about the variable/object they are creating. Developers using language like c++ really need to understand how the memory allocation works and need to free up unused memory to keep their application stand by.
Let me know you thoughts.
Thanks