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!")