Allocation Speed and Lifetime
Stack allocation is a bump pointer: increment the stack pointer and you have memory. A single instruction, extremely fast. The memory is automatically freed when the function returns. Stack is ideal for function-local variables, parameters, and return addresses.
Heap allocation calls a memory manager, which searches the free list, splits a block, and updates metadata. Much slower than stack. Heap memory persists until explicitly freed (manual management) or the garbage collector reclaims it. Heap is necessary for objects that outlive their allocating function, or whose size is unknown at compile time.
Trade-offs and Practical Constraints
Stack is limited in size (typically a few megabytes per thread on 64-bit systems). The heap can grow to available RAM. Stack memory is local to the CPU core and cache-friendly; heap memory is global and depends on allocator behavior. Stack frames have clear ownership (the function that owns the frame); heap objects require careful lifetime management or garbage collection.
Languages like Rust use stack-by-default with explicit heap allocation through Box, Rc, and Arc, giving programmers control over placement. C and C++ require manual heap management. Garbage-collected languages hide heap allocation but pay a GC overhead. Most performance-critical code carefully minimizes heap allocation in hot paths by using stack-allocated fixed-size arrays, object pools, or arena allocators.