Source: Stack Overflow
I am merely reproducing from the stack overflow. This is for my own study and reference purpose.
Stack and Heap are implementation specific and may vary
across compilers and processor architectures. However, here is a
simplified explanation.
- Both the stack and the heap are memory areas allocated from the
underlying operating system (often virtual memory that is mapped to
physical memory on demand).
- In a multi-threaded environment each thread will have its own
completely independent stack but they will share the heap. Concurrent
access has to be controlled on the heap and is not possible on the
stack.
The heap
- The heap contains a linked list of used and free blocks. New allocations on the heap (by
new
or malloc
)
are satisfied by creating a suitable block from one of the free blocks.
This requires updating list of blocks on the heap. This meta information about the blocks on the heap is also stored on the heap often in a small area just in front of every block.
- As the heap grows new blocks are often allocated from lower
addresses towards higher addresses. Thus you can think of the heap as a heap
of memory blocks that grows in size as memory is allocated. If the heap
is too small for an allocation the size can often be increased by
acquiring more memory from the underlying operating system.
- Allocating and deallocating many small blocks may leave the heap in a
state where there are a lot of small free blocks interspersed between
the used blocks. A request to allocate a large block may fail because
none of the free blocks are large enough to satisfy the allocation
request even though the combined size of the free blocks may be large
enough. This is called heap fragmentation.
- When a used block that is adjacent to a free block is deallocated
the new free block may be merged with the adjacent free block to create a
larger free block effectively reducing the fragmentation of the heap.
The stack
- The stack often works in close tandem with a special register on the CPU named the stack pointer. Initially the stack pointer points to the top of the stack (the highest address on the stack).
- The CPU has special instructions for pushing values onto the stack and popping them back from the stack. Each push stores the value at the current location of the stack pointer and decreases the stack pointer. A pop retrieves the value pointed to by the stack pointer and then increases the stack pointer (don't be confused by the fact that adding a value to the stack decreases the stack pointer and removing a value increases it. Remember that the stack grows to the bottom). The values stored and retrieved are the values of the CPU registers.
- When a function is called the CPU uses special instructions that push the current instruction pointer,
i.e. the address of the code executing on the stack. The CPU then jumps
to the function by setting the
instruction pointer to the address of the function called. Later, when
the function returns, the old instruction pointer is popped from the
stack and execution resumes at the code just after the call to the
function.
- When a function is entered, the stack pointer is decreased to
allocate more space on the stack for local (automatic) variables. If the
function has one local 32 bit variable four bytes are set aside on the
stack. When the function returns, the stack pointer is moved back to
free the allocated area.
- If a function has parameters, these are pushed onto the stack before
the call to the function. The code in the function is then able to
navigate up the stack from the current stack pointer to locate these
values.
- Nesting function calls work like a charm. Each new call will
allocate function parameters, the return address and space for local
variables and these activation records can be stacked for nested calls and will unwind in the correct way when the functions return.
- As the stack is a limited block of memory, you can cause a stack overflow
by calling too many nested functions and/or allocating too much space
for local variables. Often the memory area used for the stack is set up
in such a way that writing below the bottom (the lowest address) of the
stack will trigger a trap or exception in the CPU. This exceptional
condition can then be caught by the runtime and converted into some kind
of stack overflow exception.
Can a function be allocated on the heap instead of a stack?
No, activation records for functions (i.e. local or automatic
variables) are allocated on the stack that is used not only to store
these variables, but also to keep track of nested function calls.
How the heap is managed is really up to the runtime environment. C uses
malloc
and C++ uses
new
, but many other languages have garbage collection.
However, the stack is a more low-level feature closely tied to the
processor architecture. Growing the heap when there is not enough space
isn't too hard since it can be implemented in the library call that
handles the heap. However, growing the stack is often impossible as the
stack overflow only is discovered when it is too late; and shutting down
the thread of execution is the only viable option.