Skip to content

Python Memory Management Best Practices

Objective: Master senior-level Python memory management patterns for production systems. When you need to optimize memory usage, when you want to prevent memory leaks, when you need enterprise-grade memory management strategiesโ€”these best practices become your weapon of choice.

Core Principles

  • Understand Python's Memory Model: Reference counting, garbage collection, and memory allocation
  • Monitor Memory Usage: Track memory consumption and identify bottlenecks
  • Prevent Memory Leaks: Avoid circular references and properly manage resources
  • Optimize Data Structures: Choose memory-efficient data structures
  • Use Memory Profiling: Identify memory hotspots and optimize accordingly

Memory Model Understanding

Python's Memory Architecture

# python/01-memory-architecture.py

"""
Understanding Python's memory model and architecture
"""

import sys
import gc
import weakref
from typing import List, Dict, Any, Optional, Callable
import tracemalloc
import psutil
import os

class MemoryAnalyzer:
    """Advanced memory analysis and monitoring"""

    def __init__(self):
        self.snapshots = []
        self.memory_traces = []
        self.reference_tracker = {}

    def get_memory_info(self) -> Dict[str, Any]:
        """Get comprehensive memory information"""
        process = psutil.Process()
        memory_info = process.memory_info()

        return {
            "rss": memory_info.rss,  # Resident Set Size
            "vms": memory_info.vms,   # Virtual Memory Size
            "percent": process.memory_percent(),
            "available": psutil.virtual_memory().available,
            "total": psutil.virtual_memory().total,
            "python_objects": len(gc.get_objects()),
            "gc_counts": gc.get_count()
        }

    def start_memory_tracing(self):
        """Start memory tracing"""
        tracemalloc.start()
        self.memory_traces.append(tracemalloc.get_traced_memory())

    def stop_memory_tracing(self) -> Dict[str, Any]:
        """Stop memory tracing and get stats"""
        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()

        return {
            "current_memory": current,
            "peak_memory": peak,
            "current_mb": current / 1024 / 1024,
            "peak_mb": peak / 1024 / 1024
        }

    def take_memory_snapshot(self) -> Dict[str, Any]:
        """Take memory snapshot"""
        snapshot = self.get_memory_info()
        self.snapshots.append(snapshot)
        return snapshot

    def compare_snapshots(self, snapshot1: int, snapshot2: int) -> Dict[str, Any]:
        """Compare two memory snapshots"""
        if snapshot1 >= len(self.snapshots) or snapshot2 >= len(self.snapshots):
            raise ValueError("Invalid snapshot indices")

        snap1 = self.snapshots[snapshot1]
        snap2 = self.snapshots[snapshot2]

        return {
            "rss_diff": snap2["rss"] - snap1["rss"],
            "vms_diff": snap2["vms"] - snap1["vms"],
            "percent_diff": snap2["percent"] - snap1["percent"],
            "objects_diff": snap2["python_objects"] - snap1["python_objects"]
        }

    def find_memory_leaks(self) -> Dict[str, Any]:
        """Find potential memory leaks"""
        # Force garbage collection
        gc.collect()

        # Get object counts by type
        object_counts = {}
        for obj in gc.get_objects():
            obj_type = type(obj).__name__
            object_counts[obj_type] = object_counts.get(obj_type, 0) + 1

        # Find objects with high counts (potential leaks)
        potential_leaks = {
            obj_type: count for obj_type, count in object_counts.items()
            if count > 1000  # Threshold for potential leaks
        }

        return {
            "object_counts": object_counts,
            "potential_leaks": potential_leaks,
            "gc_counts": gc.get_count(),
            "total_objects": len(gc.get_objects())
        }

class ReferenceTracker:
    """Track object references and prevent leaks"""

    def __init__(self):
        self.tracked_objects = {}
        self.weak_refs = {}
        self.circular_refs = []

    def track_object(self, obj: Any, name: str) -> str:
        """Track an object and return tracking ID"""
        obj_id = id(obj)
        self.tracked_objects[obj_id] = {
            "object": obj,
            "name": name,
            "type": type(obj).__name__,
            "ref_count": sys.getrefcount(obj)
        }
        return str(obj_id)

    def create_weak_reference(self, obj: Any, callback: Optional[Callable] = None) -> weakref.ref:
        """Create weak reference to object"""
        weak_ref = weakref.ref(obj, callback)
        self.weak_refs[id(obj)] = weak_ref
        return weak_ref

    def check_circular_references(self) -> List[Dict[str, Any]]:
        """Check for circular references"""
        circular_refs = []

        for obj in gc.get_objects():
            if gc.is_tracked(obj):
                referrers = gc.get_referrers(obj)
                for referrer in referrers:
                    if gc.is_tracked(referrer):
                        # Check if they reference each other
                        if obj in gc.get_referrers(referrer):
                            circular_refs.append({
                                "obj1": type(obj).__name__,
                                "obj2": type(referrer).__name__,
                                "obj1_id": id(obj),
                                "obj2_id": id(referrer)
                            })

        self.circular_refs = circular_refs
        return circular_refs

    def get_reference_info(self, obj_id: str) -> Optional[Dict[str, Any]]:
        """Get reference information for tracked object"""
        obj_id_int = int(obj_id)
        if obj_id_int in self.tracked_objects:
            obj_info = self.tracked_objects[obj_id_int]
            return {
                "name": obj_info["name"],
                "type": obj_info["type"],
                "ref_count": sys.getrefcount(obj_info["object"]),
                "is_tracked": gc.is_tracked(obj_info["object"])
            }
        return None

    def cleanup_tracked_objects(self):
        """Cleanup tracked objects"""
        self.tracked_objects.clear()
        self.weak_refs.clear()
        self.circular_refs.clear()

# Usage examples
def example_memory_analysis():
    """Example memory analysis usage"""
    analyzer = MemoryAnalyzer()

    # Take initial snapshot
    initial_snapshot = analyzer.take_memory_snapshot()
    print(f"Initial memory: {initial_snapshot['rss'] / 1024 / 1024:.2f} MB")

    # Create some objects
    data = [i for i in range(10000)]

    # Take second snapshot
    second_snapshot = analyzer.take_memory_snapshot()
    print(f"After creating data: {second_snapshot['rss'] / 1024 / 1024:.2f} MB")

    # Compare snapshots
    comparison = analyzer.compare_snapshots(0, 1)
    print(f"Memory difference: {comparison['rss_diff'] / 1024 / 1024:.2f} MB")

    # Check for leaks
    leak_info = analyzer.find_memory_leaks()
    print(f"Potential leaks: {leak_info['potential_leaks']}")

def example_reference_tracking():
    """Example reference tracking usage"""
    tracker = ReferenceTracker()

    # Create and track objects
    obj1 = [1, 2, 3]
    obj2 = {"key": "value"}

    id1 = tracker.track_object(obj1, "list_object")
    id2 = tracker.track_object(obj2, "dict_object")

    # Get reference info
    info1 = tracker.get_reference_info(id1)
    info2 = tracker.get_reference_info(id2)

    print(f"Object 1 ref count: {info1['ref_count']}")
    print(f"Object 2 ref count: {info2['ref_count']}")

    # Check for circular references
    circular_refs = tracker.check_circular_references()
    print(f"Circular references found: {len(circular_refs)}")

Garbage Collection Management

# python/02-garbage-collection.py

"""
Advanced garbage collection management and optimization
"""

import gc
import sys
import time
from typing import List, Dict, Any, Optional, Callable
import weakref
from contextlib import contextmanager

class GarbageCollectionManager:
    """Advanced garbage collection management"""

    def __init__(self):
        self.gc_stats = []
        self.collection_times = []
        self.thresholds = gc.get_threshold()

    def get_gc_stats(self) -> Dict[str, Any]:
        """Get comprehensive GC statistics"""
        counts = gc.get_count()
        stats = {
            "generation_0": counts[0],
            "generation_1": counts[1],
            "generation_2": counts[2],
            "thresholds": self.thresholds,
            "total_objects": len(gc.get_objects()),
            "tracked_objects": len([obj for obj in gc.get_objects() if gc.is_tracked(obj)])
        }

        self.gc_stats.append(stats)
        return stats

    def force_collection(self) -> Dict[str, Any]:
        """Force garbage collection and measure performance"""
        start_time = time.time()

        # Get initial stats
        initial_stats = self.get_gc_stats()

        # Force collection
        collected = gc.collect()

        # Get final stats
        final_stats = self.get_gc_stats()
        collection_time = time.time() - start_time

        self.collection_times.append(collection_time)

        return {
            "collected_objects": collected,
            "collection_time": collection_time,
            "initial_objects": initial_stats["total_objects"],
            "final_objects": final_stats["total_objects"],
            "objects_freed": initial_stats["total_objects"] - final_stats["total_objects"]
        }

    def optimize_gc_thresholds(self, target_objects: int = 10000):
        """Optimize GC thresholds based on object count"""
        current_objects = len(gc.get_objects())

        if current_objects > target_objects:
            # Increase thresholds to reduce GC frequency
            new_thresholds = (
                self.thresholds[0] * 2,
                self.thresholds[1] * 2,
                self.thresholds[2] * 2
            )
            gc.set_threshold(*new_thresholds)
            self.thresholds = new_thresholds
            return True

        return False

    def disable_gc(self):
        """Disable garbage collection"""
        gc.disable()

    def enable_gc(self):
        """Enable garbage collection"""
        gc.enable()

    @contextmanager
    def gc_context(self, enabled: bool = True):
        """Context manager for GC control"""
        original_state = gc.isenabled()

        if enabled:
            gc.enable()
        else:
            gc.disable()

        try:
            yield
        finally:
            if original_state:
                gc.enable()
            else:
                gc.disable()

class MemoryEfficientDataStructures:
    """Memory-efficient data structure implementations"""

    @staticmethod
    def memory_efficient_list(size: int) -> List[int]:
        """Create memory-efficient list"""
        # Use generator for large lists
        return [i for i in range(size)]

    @staticmethod
    def memory_efficient_dict(keys: List[str], values: List[Any]) -> Dict[str, Any]:
        """Create memory-efficient dictionary"""
        # Use dict comprehension
        return {k: v for k, v in zip(keys, values)}

    @staticmethod
    def memory_efficient_set(items: List[Any]) -> set:
        """Create memory-efficient set"""
        return set(items)

    @staticmethod
    def memory_efficient_string_concatenation(strings: List[str]) -> str:
        """Memory-efficient string concatenation"""
        # Use join instead of +=
        return ''.join(strings)

    @staticmethod
    def memory_efficient_file_processing(file_path: str, chunk_size: int = 8192):
        """Memory-efficient file processing"""
        with open(file_path, 'r') as file:
            while True:
                chunk = file.read(chunk_size)
                if not chunk:
                    break
                yield chunk

class WeakReferenceManager:
    """Manage weak references to prevent memory leaks"""

    def __init__(self):
        self.weak_refs = {}
        self.callbacks = {}

    def create_weak_reference(self, obj: Any, name: str, callback: Optional[Callable] = None) -> weakref.ref:
        """Create weak reference with callback"""
        def cleanup_callback(weak_ref):
            if name in self.weak_refs:
                del self.weak_refs[name]
            if name in self.callbacks:
                del self.callbacks[name]
            if callback:
                callback(weak_ref)

        weak_ref = weakref.ref(obj, cleanup_callback)
        self.weak_refs[name] = weak_ref
        if callback:
            self.callbacks[name] = callback

        return weak_ref

    def get_weak_reference(self, name: str) -> Optional[Any]:
        """Get object from weak reference"""
        if name in self.weak_refs:
            return self.weak_refs[name]()
        return None

    def cleanup_weak_references(self):
        """Cleanup all weak references"""
        self.weak_refs.clear()
        self.callbacks.clear()

# Usage examples
def example_gc_management():
    """Example garbage collection management"""
    gc_manager = GarbageCollectionManager()

    # Get initial GC stats
    initial_stats = gc_manager.get_gc_stats()
    print(f"Initial objects: {initial_stats['total_objects']}")

    # Create some objects
    data = [i for i in range(10000)]

    # Force collection
    collection_result = gc_manager.force_collection()
    print(f"Collected {collection_result['collected_objects']} objects")
    print(f"Collection time: {collection_result['collection_time']:.4f}s")

    # Optimize thresholds
    optimized = gc_manager.optimize_gc_thresholds()
    print(f"GC thresholds optimized: {optimized}")

def example_memory_efficient_structures():
    """Example memory-efficient data structures"""
    # Memory-efficient list
    large_list = MemoryEfficientDataStructures.memory_efficient_list(10000)
    print(f"List size: {sys.getsizeof(large_list)} bytes")

    # Memory-efficient string concatenation
    strings = [f"string_{i}" for i in range(1000)]
    result = MemoryEfficientDataStructures.memory_efficient_string_concatenation(strings)
    print(f"Concatenated string length: {len(result)}")

    # Memory-efficient file processing
    # This would process a file in chunks
    # for chunk in MemoryEfficientDataStructures.memory_efficient_file_processing("large_file.txt"):
    #     process_chunk(chunk)

Memory Optimization Patterns

Object Pooling

# python/03-memory-optimization.py

"""
Memory optimization patterns including object pooling and caching
"""

import gc
import sys
import time
from typing import List, Dict, Any, Optional, Type, Callable
from collections import deque
import threading

class ObjectPool:
    """Generic object pool for memory optimization"""

    def __init__(self, factory: Callable, max_size: int = 100, reset_func: Optional[Callable] = None):
        self.factory = factory
        self.max_size = max_size
        self.reset_func = reset_func
        self.pool = deque()
        self.lock = threading.Lock()
        self.created_count = 0
        self.reused_count = 0

    def get_object(self) -> Any:
        """Get object from pool"""
        with self.lock:
            if self.pool:
                obj = self.pool.popleft()
                self.reused_count += 1
            else:
                obj = self.factory()
                self.created_count += 1

            # Reset object if reset function provided
            if self.reset_func:
                self.reset_func(obj)

            return obj

    def return_object(self, obj: Any):
        """Return object to pool"""
        with self.lock:
            if len(self.pool) < self.max_size:
                self.pool.append(obj)

    def get_stats(self) -> Dict[str, Any]:
        """Get pool statistics"""
        with self.lock:
            return {
                "pool_size": len(self.pool),
                "created_count": self.created_count,
                "reused_count": self.reused_count,
                "total_objects": self.created_count + self.reused_count
            }

    def clear_pool(self):
        """Clear object pool"""
        with self.lock:
            self.pool.clear()

class MemoryCache:
    """Memory-efficient cache with size limits"""

    def __init__(self, max_size: int = 1000, max_memory_mb: int = 100):
        self.max_size = max_size
        self.max_memory_bytes = max_memory_mb * 1024 * 1024
        self.cache = {}
        self.access_order = deque()
        self.current_memory = 0
        self.lock = threading.Lock()

    def get(self, key: str) -> Optional[Any]:
        """Get value from cache"""
        with self.lock:
            if key in self.cache:
                # Update access order
                if key in self.access_order:
                    self.access_order.remove(key)
                self.access_order.append(key)
                return self.cache[key]
            return None

    def put(self, key: str, value: Any) -> None:
        """Put value in cache"""
        with self.lock:
            # Calculate memory usage
            value_size = sys.getsizeof(value)

            # Remove items if cache is full
            while (len(self.cache) >= self.max_size or 
                   self.current_memory + value_size > self.max_memory_bytes):
                if not self.access_order:
                    break

                oldest_key = self.access_order.popleft()
                if oldest_key in self.cache:
                    old_value = self.cache[oldest_key]
                    self.current_memory -= sys.getsizeof(old_value)
                    del self.cache[oldest_key]

            # Add new item
            self.cache[key] = value
            self.current_memory += value_size
            self.access_order.append(key)

    def clear(self) -> None:
        """Clear cache"""
        with self.lock:
            self.cache.clear()
            self.access_order.clear()
            self.current_memory = 0

    def get_stats(self) -> Dict[str, Any]:
        """Get cache statistics"""
        with self.lock:
            return {
                "size": len(self.cache),
                "memory_usage": self.current_memory,
                "memory_usage_mb": self.current_memory / 1024 / 1024,
                "max_size": self.max_size,
                "max_memory_mb": self.max_memory_bytes / 1024 / 1024
            }

class MemoryMonitor:
    """Monitor memory usage and provide alerts"""

    def __init__(self, warning_threshold: float = 80.0, critical_threshold: float = 95.0):
        self.warning_threshold = warning_threshold
        self.critical_threshold = critical_threshold
        self.monitoring = False
        self.monitor_thread = None
        self.alerts = []

    def start_monitoring(self, interval: float = 1.0):
        """Start memory monitoring"""
        if self.monitoring:
            return

        self.monitoring = True
        self.monitor_thread = threading.Thread(
            target=self._monitor_loop,
            args=(interval,),
            daemon=True
        )
        self.monitor_thread.start()

    def stop_monitoring(self):
        """Stop memory monitoring"""
        self.monitoring = False
        if self.monitor_thread:
            self.monitor_thread.join()

    def _monitor_loop(self, interval: float):
        """Memory monitoring loop"""
        while self.monitoring:
            try:
                memory_percent = psutil.virtual_memory().percent

                if memory_percent >= self.critical_threshold:
                    self.alerts.append({
                        "level": "critical",
                        "memory_percent": memory_percent,
                        "timestamp": time.time()
                    })
                elif memory_percent >= self.warning_threshold:
                    self.alerts.append({
                        "level": "warning",
                        "memory_percent": memory_percent,
                        "timestamp": time.time()
                    })

                time.sleep(interval)
            except Exception as e:
                print(f"Memory monitoring error: {e}")
                time.sleep(interval)

    def get_alerts(self) -> List[Dict[str, Any]]:
        """Get memory alerts"""
        return self.alerts.copy()

    def clear_alerts(self):
        """Clear memory alerts"""
        self.alerts.clear()

# Usage examples
def example_object_pooling():
    """Example object pooling usage"""
    # Create object pool
    def create_expensive_object():
        return {"data": [i for i in range(1000)], "timestamp": time.time()}

    def reset_object(obj):
        obj["data"].clear()
        obj["timestamp"] = time.time()

    pool = ObjectPool(create_expensive_object, max_size=10, reset_func=reset_object)

    # Use objects from pool
    obj1 = pool.get_object()
    obj2 = pool.get_object()

    # Return objects to pool
    pool.return_object(obj1)
    pool.return_object(obj2)

    # Get pool stats
    stats = pool.get_stats()
    print(f"Pool stats: {stats}")

def example_memory_cache():
    """Example memory cache usage"""
    cache = MemoryCache(max_size=100, max_memory_mb=10)

    # Add items to cache
    for i in range(50):
        cache.put(f"key_{i}", f"value_{i}" * 100)

    # Get cache stats
    stats = cache.get_stats()
    print(f"Cache stats: {stats}")

    # Get item from cache
    value = cache.get("key_10")
    print(f"Retrieved value: {value}")

def example_memory_monitoring():
    """Example memory monitoring usage"""
    monitor = MemoryMonitor(warning_threshold=70.0, critical_threshold=90.0)

    # Start monitoring
    monitor.start_monitoring(interval=0.5)

    # Simulate memory usage
    data = []
    for i in range(1000):
        data.append([j for j in range(1000)])
        time.sleep(0.01)

    # Check alerts
    alerts = monitor.get_alerts()
    print(f"Memory alerts: {len(alerts)}")

    # Stop monitoring
    monitor.stop_monitoring()

Memory Leak Prevention

Resource Management

# python/04-memory-leak-prevention.py

"""
Memory leak prevention patterns and resource management
"""

import gc
import sys
import weakref
from typing import List, Dict, Any, Optional, Callable, ContextManager
from contextlib import contextmanager
import threading
import time

class ResourceManager:
    """Advanced resource management to prevent memory leaks"""

    def __init__(self):
        self.resources = {}
        self.cleanup_handlers = {}
        self.lock = threading.Lock()

    def register_resource(self, resource_id: str, resource: Any, cleanup_func: Optional[Callable] = None):
        """Register resource with cleanup function"""
        with self.lock:
            self.resources[resource_id] = resource
            if cleanup_func:
                self.cleanup_handlers[resource_id] = cleanup_func

    def unregister_resource(self, resource_id: str):
        """Unregister resource and cleanup"""
        with self.lock:
            if resource_id in self.resources:
                # Call cleanup function if exists
                if resource_id in self.cleanup_handlers:
                    try:
                        self.cleanup_handlers[resource_id]()
                    except Exception as e:
                        print(f"Cleanup error for {resource_id}: {e}")

                del self.resources[resource_id]
                if resource_id in self.cleanup_handlers:
                    del self.cleanup_handlers[resource_id]

    def cleanup_all_resources(self):
        """Cleanup all registered resources"""
        with self.lock:
            for resource_id in list(self.resources.keys()):
                self.unregister_resource(resource_id)

    def get_resource(self, resource_id: str) -> Optional[Any]:
        """Get registered resource"""
        with self.lock:
            return self.resources.get(resource_id)

    def list_resources(self) -> List[str]:
        """List all registered resource IDs"""
        with self.lock:
            return list(self.resources.keys())

class CircularReferenceBreaker:
    """Break circular references to prevent memory leaks"""

    def __init__(self):
        self.tracked_objects = {}
        self.weak_refs = {}

    def track_object(self, obj: Any, name: str) -> str:
        """Track object for circular reference detection"""
        obj_id = id(obj)
        self.tracked_objects[obj_id] = {
            "object": obj,
            "name": name,
            "type": type(obj).__name__
        }
        return str(obj_id)

    def create_weak_reference(self, obj: Any, name: str) -> weakref.ref:
        """Create weak reference to break circular references"""
        def cleanup_callback(weak_ref):
            if name in self.weak_refs:
                del self.weak_refs[name]

        weak_ref = weakref.ref(obj, cleanup_callback)
        self.weak_refs[name] = weak_ref
        return weak_ref

    def break_circular_references(self) -> List[Dict[str, Any]]:
        """Break circular references and return info about broken references"""
        broken_refs = []

        # Find circular references
        for obj in gc.get_objects():
            if gc.is_tracked(obj):
                referrers = gc.get_referrers(obj)
                for referrer in referrers:
                    if gc.is_tracked(referrer) and obj in gc.get_referrers(referrer):
                        # Break circular reference by creating weak reference
                        weak_ref = weakref.ref(obj)
                        broken_refs.append({
                            "obj_type": type(obj).__name__,
                            "referrer_type": type(referrer).__name__,
                            "weak_ref": weak_ref
                        })

        return broken_refs

    def cleanup_tracked_objects(self):
        """Cleanup tracked objects"""
        self.tracked_objects.clear()
        self.weak_refs.clear()

class MemoryLeakDetector:
    """Detect and prevent memory leaks"""

    def __init__(self):
        self.baseline_objects = 0
        self.baseline_memory = 0
        self.leak_threshold = 1000  # Objects
        self.memory_threshold = 50 * 1024 * 1024  # 50MB

    def set_baseline(self):
        """Set baseline for leak detection"""
        gc.collect()
        self.baseline_objects = len(gc.get_objects())
        self.baseline_memory = psutil.Process().memory_info().rss

    def check_for_leaks(self) -> Dict[str, Any]:
        """Check for potential memory leaks"""
        gc.collect()
        current_objects = len(gc.get_objects())
        current_memory = psutil.Process().memory_info().rss

        object_diff = current_objects - self.baseline_objects
        memory_diff = current_memory - self.baseline_memory

        leak_detected = (
            object_diff > self.leak_threshold or
            memory_diff > self.memory_threshold
        )

        return {
            "leak_detected": leak_detected,
            "object_diff": object_diff,
            "memory_diff": memory_diff,
            "memory_diff_mb": memory_diff / 1024 / 1024,
            "current_objects": current_objects,
            "current_memory": current_memory,
            "baseline_objects": self.baseline_objects,
            "baseline_memory": self.baseline_memory
        }

    def force_cleanup(self):
        """Force cleanup to prevent leaks"""
        # Force garbage collection
        gc.collect()

        # Clear caches if they exist
        for obj in gc.get_objects():
            if hasattr(obj, 'clear') and callable(obj.clear):
                try:
                    obj.clear()
                except:
                    pass

@contextmanager
def memory_context(monitor_leaks: bool = True):
    """Context manager for memory leak monitoring"""
    detector = MemoryLeakDetector()
    detector.set_baseline()

    try:
        yield detector
    finally:
        if monitor_leaks:
            leak_info = detector.check_for_leaks()
            if leak_info["leak_detected"]:
                print(f"Memory leak detected: {leak_info}")
                detector.force_cleanup()

# Usage examples
def example_resource_management():
    """Example resource management usage"""
    manager = ResourceManager()

    # Register resources
    def cleanup_file(file_obj):
        if hasattr(file_obj, 'close'):
            file_obj.close()

    # Simulate resource registration
    resource1 = {"data": "resource1"}
    resource2 = {"data": "resource2"}

    manager.register_resource("resource1", resource1, cleanup_file)
    manager.register_resource("resource2", resource2, cleanup_file)

    # Use resources
    retrieved = manager.get_resource("resource1")
    print(f"Retrieved resource: {retrieved}")

    # Cleanup resources
    manager.cleanup_all_resources()
    print("Resources cleaned up")

def example_memory_leak_detection():
    """Example memory leak detection usage"""
    with memory_context(monitor_leaks=True) as detector:
        # Simulate memory usage
        data = []
        for i in range(1000):
            data.append([j for j in range(1000)])

        # Check for leaks
        leak_info = detector.check_for_leaks()
        print(f"Leak detection: {leak_info}")

def example_circular_reference_breaking():
    """Example circular reference breaking usage"""
    breaker = CircularReferenceBreaker()

    # Create objects that might have circular references
    obj1 = {"name": "object1"}
    obj2 = {"name": "object2"}

    # Create circular reference
    obj1["ref"] = obj2
    obj2["ref"] = obj1

    # Track objects
    breaker.track_object(obj1, "obj1")
    breaker.track_object(obj2, "obj2")

    # Break circular references
    broken_refs = breaker.break_circular_references()
    print(f"Broken references: {len(broken_refs)}")

    # Cleanup
    breaker.cleanup_tracked_objects()

TL;DR Runbook

Quick Start

# 1. Monitor memory usage
from python.memory_management import MemoryAnalyzer
analyzer = MemoryAnalyzer()
memory_info = analyzer.get_memory_info()
print(f"Memory usage: {memory_info['rss'] / 1024 / 1024:.2f} MB")

# 2. Use object pooling
from python.memory_optimization import ObjectPool
pool = ObjectPool(create_expensive_object, max_size=10)
obj = pool.get_object()
# Use object
pool.return_object(obj)

# 3. Monitor for leaks
from python.memory_leak_prevention import memory_context
with memory_context(monitor_leaks=True) as detector:
    # Your code here
    pass

# 4. Force garbage collection
import gc
gc.collect()

Essential Patterns

# Complete memory management setup
def setup_memory_management():
    """Setup complete memory management environment"""

    # Memory analyzer
    analyzer = MemoryAnalyzer()

    # Object pool
    pool = ObjectPool(create_expensive_object, max_size=100)

    # Memory cache
    cache = MemoryCache(max_size=1000, max_memory_mb=100)

    # Resource manager
    resource_manager = ResourceManager()

    # Memory monitor
    monitor = MemoryMonitor(warning_threshold=80.0, critical_threshold=95.0)
    monitor.start_monitoring()

    print("Memory management setup complete!")

This guide provides the complete machinery for Python memory management. Each pattern includes implementation examples, optimization strategies, and real-world usage patterns for enterprise memory management.