The Stack is more or less responsible for keeping track of what's executing in our code (or what's been "called"). The Heap is more or less responsible for keeping track of our objects (our data, well... most of it; we'll get to that later).
What goes on the Stack and Heap?
We have four main types of things we'll be putting in the Stack and Heap as our code is executing: Value Types, Reference Types, Pointers, and Instructions.
Value Types:
In C#, all the "things" declared with the following list of type declarations are Value types (because they are from System.ValueType):
bool
byte
char
decimal
double
enum
float
int
long
sbyte
short
struct
uint
ulong
ushort
Reference Types:
All the "things" declared with the types in this list are Reference types (and inherit from System.Object, except, of course, for object which is the System.Object object):
class
interface
delegate
object
string
Pointers:
The third type of "thing" to be put in our memory management scheme is a Reference to a Type. A Reference is often referred to as a Pointer. We don't explicitly use Pointers, they are managed by the Common Language Runtime (CLR). A Pointer (or Reference) is different than a Reference Type in that when we say something is a Reference Type, it means we access it through a Pointer. A Pointer is a chunk of space in memory that points to another space in memory. A Pointer takes up space just like any other thing that we're putting in the Stack and Heap and its value is either a memory address or null.
How is it decided what goes where?
A Reference Type always goes on the Heap;
Value Types and Pointers always go where they were declared
Example: For stake
Take the following method:
public int AddFive(int pValue)
{
int result;
result = pValue + 5;
return result;
}
NOTE : the method does not live on the stack and is illustrated just for reference.
Next, control (the thread executing the method) is passed to the instructions to the AddFive() method which lives in our type's method table, a JIT compilation is performed if this is the first time we are hitting the method.
As the method executes, we need some memory for the "result" variable and it is allocated on the Stack.
The method finishes execution and our result is returned.
And all memory allocated on the Stack is cleaned up by moving a pointer to the available memory address where AddFive() started and we go down to the previous method on the stack (not seen here).
Example : for heap
If we have the following MyInt class (which is a Reference Type because it is a class):
public class MyInt
{
public int MyValue;
}
and the following method is executing:
public MyInt AddFive(int pValue)
{
MyInt result = new MyInt();
result.MyValue = pValue + 5;
return result;
}
Then just as before, the thread starts executing the method and its parameters are placed on sthe thread's stack.
Because MyInt is a Reference Type, it is placed on the Heap and referenced by a Pointer on the Stack.
After AddFive() is finished executing (like in the first example), and we are cleaning up...
we're left with an orphaned MyInt in the Heap (there is no longer anyone in the Stack standing around pointing to MyInt)!
This is where the Garbage Collection (GC) comes into play. Once our program reaches a certain memory threshold and we need more Heap space, our GC will kick off. The GC will stop all running threads (a FULL STOP), find all objects in the Heap that are not being accessed by the main program and delete them. The GC will then reorganize all the objects left in the Heap to make space and adjust all the Pointers to these objects in both the Stack and the Heap.
Note : This blog is taken from codeproject website, as it was well explained there.
No comments:
Post a Comment