Skip to content

Stack & Heap Overview

Two Memory Areas

1. Stack

Function call frames and local names:

def function():
    x = 10          # Name on stack
    y = 20          # Name on stack
    return x + y

# Stack grows/shrinks with calls

2. Heap

Objects storage:

x = [1, 2, 3]       # Object on heap
y = "hello"         # Object on heap
z = 42              # Object on heap

Stack Properties

1. Fast Access

def compute():
    a = 10          # Fast stack access
    b = 20
    return a + b

2. Automatic Management

def f():
    x = 10          # Stack allocated
    return x
    # x deallocated when f returns

3. Limited Size

def recursive(n):
    if n == 0:
        return
    return recursive(n - 1)

# Too deep causes stack overflow

Heap Properties

1. Dynamic Size

# Can grow as needed
lst = []
for i in range(1000000):
    lst.append(i)   # Heap grows

2. Manual Management

x = [1, 2, 3]       # Heap allocated
# Stays until GC'd
del x               # Remove reference

3. Slower Access

# Heap access slower than stack
# But necessary for objects

What Goes Where

1. Stack

  • Function frames
  • Local name bindings
  • Return addresses
  • Parameters

2. Heap

  • All Python objects
  • Lists, dicts, strings
  • Integers, floats
  • User-defined objects

Memory Visualization

1. Example

def process():
    x = [1, 2, 3]
    y = x
    return y

Memory:

Stack:
  [process frame]
    x -----> 
    y -----> [1, 2, 3] (Heap)

Heap:
  [1, 2, 3] object

2. Multiple Frames

def outer():
    a = [1, 2]
    return inner(a)

def inner(param):
    b = param
    return b

Stack:

[outer frame]
  a -----> [1, 2] (Heap)

[inner frame]  
  param -----> [1, 2] (Heap)
  b -----> [1, 2] (Heap)

Frame Objects

1. Stack Frame

import inspect

def example():
    frame = inspect.currentframe()
    print(frame.f_locals)

example()

2. Frame Info

def show_frame():
    frame = inspect.currentframe()
    print(f"Function: {frame.f_code.co_name}")
    print(f"Line: {frame.f_lineno}")

show_frame()

Summary

1. Stack

  • Fast, limited size
  • Function frames
  • Name bindings
  • Auto management

2. Heap

  • Slower, dynamic size
  • All objects
  • Manual/GC management
  • Longer lifetime

Runnable Example: stack_vs_heap.py

"""
01_stack_vs_heap.py - Stack vs Heap Memory (Conceptual Foundation)
Topic #23: Memory and Namespace
"""

# =============================================================================
# Main
# =============================================================================

if __name__ == "__main__":

    print("=" * 70)
    print("STACK VS HEAP MEMORY")
    print("=" * 70)

    print("""
    COMPUTER MEMORY (RAM) IS DIVIDED INTO:

    STACK                          HEAP
    - Organized (frames)          - Unorganized (flexible)
    - Automatic management        - Requires GC
    - Fixed size per frame        - Variable size allocations
    - Very fast                   - Slower
    - LIFO structure              - Random access
    - Function calls              - All Python objects
    - Local variable NAMES        - Everything is an object!

    KEY INSIGHT:
    Variable NAMES live on stack
    Variable OBJECTS live on heap
    """)

    # Simple example
    x = 42
    name = "Alice"
    numbers = [1, 2, 3]

    print(f"\nCreated: x={x}, name='{name}', numbers={numbers}")

    print("""
    MEMORY MODEL:

    STACK:                  HEAP:
    ┌──────────┐           ┌─────────────┐
    │ x    ────┼──────────→│ int: 42     │
    │ name ────┼──────────→│ str: "Alice"│
    │ numbers ─┼──────────→│ list: [...]│
    └──────────┘           └─────────────┘

    Stack holds NAMES (references)
    Heap holds OBJECTS (actual data)
    """)

    # Function call stack
    def outer():
        print("  → outer() called")
        inner()
        print("  ← outer() returns")

    def inner():
        print("    → inner() called")
        x = 100
        print(f"    x = {x}")
        print("    ← inner() returns")

    print("\nFunction call stack demonstration:")
    outer()

    print("""
    STACK FRAMES:

    Start:           [global]
    Call outer():    [outer] [global]
    Call inner():    [inner] [outer] [global]  ← Stack grows
    inner returns:   [outer] [global]
    outer returns:   [global]                  ← Stack shrinks

    Each function gets its own frame!
    """)

    print("\nKey takeaways:")
    print("1. Stack: Fast, automatic, organized")
    print("2. Heap: Flexible, requires GC, all objects")
    print("3. Names on stack point to objects on heap")
    print("4. Understanding this helps debug memory issues")

    print("\nSee exercises.py for practice!")