EasyStack

Stack Memory

Where does your data live when your program runs? Understanding stack memory vs heap memory is fundamental to writing efficient, bug-free code.

What Is Stack Memory?

Stack memory is a region of memory used for static memory allocation. It stores local variables, function parameters, and return addresses. It follows LIFO (Last In, First Out) behavior, which is why it is called a "stack."

When a function is called, the system allocates a block of memory on the stack for that function's local data. When the function returns, that block is automatically freed. No manual management is needed. This makes stack allocation extremely fast, typically just moving a pointer forward or backward by a few bytes.

Stack memory has a fixed size set by the operating system, usually between 1 MB and 8 MB. If you try to use more, you get a stack overflow error.

Learn how the call stack uses this memory

What Is Heap Memory?

Heap memory is a region used for dynamic memory allocation. When you create an object, array, or allocate memory at runtime (using new in C++, malloc in C, or object literals in JavaScript/Python), the memory comes from the heap.

The heap is much larger than the stack, limited only by available system RAM. However, heap allocation is slower because the system must find a free block of the right size and keep track of it. In garbage-collected languages, the heap is managed by the garbage collector, which periodically reclaims unused memory.

Stack analogies for understanding allocation patterns

Stack vs Heap Comparison

FeatureStack MemoryHeap Memory
SpeedVery fast (pointer arithmetic)Slower (allocation algorithm)
SizeSmall (1-8 MB typical)Limited by available RAM
AllocationAutomatic (compiler/OS)Manual or garbage-collected
LifetimeScope of the functionUntil explicitly freed or GC'd
FragmentationNone (contiguous)Possible over time
AccessDirect (fast CPU cache)Indirect (pointer/reference)
Thread safetyEach thread has its own stackShared, requires synchronization

How Local Variables Use Stack Memory

When you declare a variable inside a function, it is stored on the stack. This includes integers, floats, booleans, characters, and pointers. The memory is allocated when the function is entered and freed when it returns.

void example() {
    int x = 10;          // stored on the stack
    double y = 3.14;     // stored on the stack
    char c = 'A';        // stored on the stack
    int *ptr = &x;       // pointer on the stack, points to stack memory
}

In higher-level languages like JavaScript and Python, primitive values (numbers, strings, booleans) are stored on the stack (or in stack frames), while objects and arrays are allocated on the heap with a reference on the stack.

Stack implementation in JavaScript

How Dynamic Allocation Uses Heap Memory

When you need memory whose size is not known at compile time, or whose lifetime extends beyond the current function, you allocate it on the heap.

// C: malloc allocates on the heap
int *arr = malloc(100 * sizeof(int));
free(arr);  // must free manually

// C++: new allocates on the heap
int *arr = new int[100];
delete[] arr;

// JavaScript: objects are allocated on the heap automatically
const obj = { name: "hello", values: [1, 2, 3] };
// garbage collector frees it when no longer referenced

// Python: everything is an object on the heap
data = [1, 2, 3]  # heap allocated, reference counted

Stack Memory Limits and Overflow

Stack memory has a fixed, relatively small size. Common causes of stack overflow include:

  • Infinite recursion: A function calling itself without a base case exhausts the stack.
  • Very large local arrays: Declaring int arr[1000000] inside a function tries to allocate millions of bytes on the stack.
  • Deep but finite recursion: Even valid recursion can overflow if the depth exceeds the stack limit.

Solutions include increasing the stack size (OS/compiler settings), converting recursion to iteration, or moving large data to the heap using dynamic allocation.

Stack complexity and limits

Memory Layout in a Running Program

When a program is loaded into memory, it is divided into several regions:

  • Text segment: Contains the compiled machine code (read-only).
  • Data segment: Contains global and static variables.
  • Heap: Grows upward from the data segment. Used for dynamic allocation.
  • Stack: Grows downward from the top of the address space. Used for function calls and local variables.

The heap and stack grow toward each other. If they meet, a stack overflow or out-of-memory condition occurs. The gap between them is the free space available for dynamic allocation.

Stack Memory in C

In C, all local variables are automatically allocated on the stack. This is called automatic storage duration. The compiler knows the exact size needed at compile time and adjusts the stack pointer accordingly.

void compute() {
    int a = 5;        // 4 bytes on stack
    double b = 2.7;   // 8 bytes on stack
    char name[20];    // 20 bytes on stack
    // all freed when function returns
}

C gives you direct control: you can use alloca() for stack allocation and malloc()/free() for heap allocation. This power comes with responsibility: forgetting to free heap memory causes leaks, and writing past stack buffers causes undefined behavior.

Stack Memory in Java, Python, and JavaScript

In managed languages, you do not directly control stack and heap allocation, but the same principles apply:

  • Java: Local primitives and references live on the stack. Objects live on the heap. The JVM manages both. Stack size can be configured with -Xss.
  • Python: Everything is an object on the heap, even integers. Function frames are on the call stack but reference heap objects. The reference limit is set by sys.getrecursionlimit().
  • JavaScript: The V8 engine stores primitive values in stack frames and objects/arrays on the heap. The garbage collector handles heap cleanup. The call stack limit is enforced by the engine.

Understanding this distinction helps you write code that avoids unnecessary heap allocations (for performance) and avoids deep recursion (to prevent stack overflow).

Key Takeaway

Stack memory is fast, automatic, and small. Heap memory is flexible, large, but slower. Know when your data lives on each one, and you will write faster, more reliable code. Avoid putting large data or deep recursion on the stack, and always free or let the garbage collector handle heap data.

Frequently Asked Questions

Why is stack memory faster than heap memory?

Stack memory is faster because it uses a simple pointer-based allocation scheme. When a function is called, the stack pointer simply moves forward to reserve space. No search is needed. Heap allocation requires finding a free block of the right size, which involves more complex algorithms and potential locking in multi-threaded programs.

What is the difference between stack overflow and heap overflow?

A stack overflow occurs when too many function calls or large local variables exhaust the fixed stack space, typically 1-8 MB. A heap overflow (or out-of-memory error) occurs when the program requests more heap memory than the operating system can provide. Stack overflow is usually caused by logic errors like infinite recursion, while heap overflow is caused by allocating too much data.

Do garbage-collected languages like Python and JavaScript use stack memory?

Yes. Even in garbage-collected languages, the call stack uses stack memory for function frames and local primitive variables. Objects, arrays, and strings are allocated on the heap. The garbage collector manages heap memory but does not touch stack memory, which is automatically managed by the function call mechanism.