Skip to main content

Garbage Collection

🚀 What You'll Learn: Python manages memory automatically. In this lesson, you'll understand how—through reference counting and garbage collection. You'll observe objects being freed, handle tricky circular references, and use the gc module to analyze memory like a professional. No manual memory management needed; just smart understanding of how Python cleans up after itself.

💬 Why This Matters

Memory management sounds abstract, but it's about trust. When you create 10,000 objects in a loop, Python automatically frees them when they're no longer needed. No crashes, no memory explosions, no cleanup code. But understanding how it works prevents subtle bugs and helps you write efficient long-running applications.

Think of Python as a responsible roommate: it cleans up your dishes (deletes objects) as soon as you're done using them. We're learning to see that process happen.


Concept: Reference Counting

Python uses reference counting as its primary memory management mechanism. Every object Python creates has a counter: "How many things are currently using me?"

How It Works

When you create an object, its reference count starts at 1. When you create another variable pointing to it, the count increases. When you delete a reference, it decreases. When the count hits zero, Python immediately frees the memory.

Loading Python environment...

Key insight: sys.getrefcount() returns one extra because the function itself holds a reference while measuring.

Why This Matters

Reference counting is simple and immediate. When your function ends, its local variables vanish, their refcounts decrease, and objects are freed instantly. No waiting for garbage collection to run—automatic cleanup as you go.

💬 AI Colearning Prompt

"When I create a list inside a function and the function returns, what happens to that list? Walk me through the reference counting process step by step."


Concept: Circular References (The Problem)

Here's where reference counting breaks: circular references. Two objects pointing to each other.

Object A → Object B
Object B → Object A (circle!)

When both refcounts are above zero but nothing external points to them, reference counting can't free them. They're "orphaned" but not technically unreferenced.

Example: Circular Reference

Loading Python environment...

Output: The __del__ methods don't print. Objects are orphaned.

The Solution: Garbage Collection

Python includes a cycle detector (separate from reference counting) that periodically finds and breaks circular references. This happens automatically unless you disable it.

Loading Python environment...

🎓 Expert Insight

In AI-native development, you trust Python's automatic memory management but understand the mechanism. When you see "memory leak" in production, you know to check for circular references. Ask your AI: "How do I detect circular references in my code?" and it'll show you profiling techniques using the gc module.


Concept: The gc Module

The gc module gives you control over garbage collection. In normal operation, you rarely need it—GC happens automatically. But understanding it helps you profile memory and debug issues.

Basic Operations

Loading Python environment...

Memory Profiling with gc Module

Loading Python environment...

Important: Reference counting handles deletion in this example. gc.collect() is mainly for circular references, which didn't exist here.

Generational Garbage Collection

Python uses generational GC: young objects (recently created) are checked frequently; old objects less frequently. This optimizes performance (most objects die young).

Loading Python environment...

🤝 Practice Exercise

Ask your AI: "Create two objects that reference each other (a circular reference). Use sys.getrefcount() to show their reference counts. Then delete both variables and use gc.collect() to prove the cycle detector freed them."

Expected Outcome: You'll observe circular references in action and understand how Python's two-tier memory management (reference counting + cycle detection) works together.


Code Examples in Action

Example 1: Observing Reference Counting

Spec Reference: FR-024 (understand reference counting), FR-025 (observe deletion)

Prompt Used: "Create a Python script that shows reference counting in action. Create an object, assign it to another variable, delete references one by one, and show refcount at each step."

Generated Code:

Loading Python environment...

Validation Steps:

  1. Run script and observe refcount increasing with each assignment
  2. Observe refcount decreasing with each del
  3. Confirm objects freed immediately when refcount drops to zero
  4. In loop: confirm temporary variables don't accumulate

Example 2: Circular References and Cycle Detection

Spec Reference: FR-027 (cycle detection)

Prompt Used: "Create a Node class with circular references. Show how del doesn't free circular objects, then use gc.collect() to detect and break the cycle."

Generated Code:

Loading Python environment...

Validation Steps:

  1. Run and observe nodes are created
  2. After del: del is NOT called (circular reference prevents freeing)
  3. After gc.collect(): del IS called (cycle detector frees them)
  4. Compare behavior with and without gc.collect()

Example 3: Memory Profiling with gc.get_objects()

Spec Reference: FR-026 (use gc module for analysis), FR-028 (profile memory)

Prompt Used: "Write a memory profiler that counts objects before and after creating different data structures. Use gc.get_objects() to track total objects."

Generated Code:

Loading Python environment...

Validation Steps:

  1. Run and observe object counts increasing
  2. After del: reference counting frees objects immediately (count drops)
  3. gc.collect() shows minimal freed (no circular refs)
  4. Compare object counts for different data structures

Example 4: Reference Counting in Functions

Spec Reference: FR-025 (automatic deletion)

Prompt Used: "Show how reference counting works when objects are passed to functions. Track refcount before, during, and after function calls."

Generated Code:

Loading Python environment...

Validation Steps:

  1. Run and observe refcount during function call (increases)
  2. After function returns: refcount decreases (reference released)
  3. In loop: temporary variables freed each iteration
  4. Verify memory doesn't accumulate

Example 5: Generational Garbage Collection

Spec Reference: FR-029 (understand when GC runs)

Prompt Used: "Demonstrate Python's generational garbage collection. Show thresholds, collection counts, and how to manually trigger collection at different generations."

Generated Code:

Loading Python environment...

Validation Steps:

  1. Run and observe default thresholds (700, 10, 10)
  2. Observe collection counts change
  3. After gc.collect(): counts reset
  4. Understand generational strategy (young objects collected frequently)

Practice Exercises

Exercise 1: Track Reference Counting Manually

Create a script that:

  1. Creates a list with three references
  2. Prints refcount after each reference creation
  3. Deletes references one by one
  4. Shows refcount at each step
  5. Confirms object is freed when refcount reaches zero

What You're Learning: Direct observation of reference counting in action.

Exercise 2: Break a Circular Reference

Write a Person class where:

  1. Each person has a best_friend attribute
  2. Create two people with circular friend relationship
  3. Delete both people
  4. Observe they're NOT freed (circular reference)
  5. Use gc.collect() to free them
  6. Confirm they're freed

What You're Learning: Identifying and resolving circular references.

Exercise 3: Profile Object Creation and Deletion

Use gc.get_objects() to:

  1. Count objects at baseline
  2. Create a dictionary with 10,000 entries
  3. Count objects (how many were created?)
  4. Delete the dictionary
  5. Count objects (how many were freed?)
  6. Verify reference counting handles deletion

What You're Learning: Memory profiling using gc module.

Exercise 4: Compare Memory Usage Across Data Structures

Create a function analyze_memory(structure_type: str) -> None: that:

  1. Creates 50,000 items in the specified structure (list, set, tuple, dict)
  2. Uses gc.get_objects() to count objects before/after
  3. Prints object counts for each structure
  4. Deletes the structure and recounts
  5. Shows how many objects each structure creates

What You're Learning: Real-world memory profiling patterns.


Try With AI

Understand Python's memory management: reference counting and garbage collection.

🔍 Explore Reference Counting:

"Explain how Python knows when to delete objects using reference counting analogy (counting who's using this object). Show counter mechanics: increases on new reference, decreases on deletion, freed at zero. Is this automatic?"

🎯 Practice Circular References:

"Help me understand circular references: show code where Object A references B and B references A. Explain why refcount never reaches zero, why reference counting can't free them, why Python needs cycle detector. Does Python fix this automatically?"

🧪 Test Memory Profiling:

"Debug memory usage: create 100K objects, show object count before/after using gc.get_objects(), delete all objects, show freed count. Explain what reference counting did. Use sys.getrefcount() to observe."

🚀 Apply Two-System Design:

"Build understanding of why Python has both reference counting AND garbage collector. Compare: reference counting (fast, immediate, 95% objects) vs cycle detector (periodic, circular refs, 5%). When would I manually call gc.collect()?"