Debugging & Profiling
Memory Profiling
Tracking memory usage and finding leaks — tracemalloc, memory_profiler, objgraph, and sys.getsizeof for memory analysis.
Interview: Memory optimization — understanding memory usage is critical for long-running applications and data processing.
Memory profiling identifies memory leaks, excessive allocations, and opportunities for optimization. Python's garbage collector handles deallocation, but circular references, cached objects, and growing collections can cause memory to increase over time. Several tools help diagnose memory issues.
Built-in Tools
sys.getsizeof(obj)— size of a single object in bytes (shallow, doesn't count contents)tracemalloc— standard library module for tracing memory allocationstracemalloc.start()— begin tracking;tracemalloc.take_snapshot()— capture stategc.get_objects()— list all objects tracked by the garbage collectorgc.collect()— force garbage collection and return number of unreachable objects
Third-Party Tools
memory_profiler—@profiledecorator shows memory per lineobjgraph— visualize object references and find memory leakspympler— track memory usage of individual objects over timemprof— plot memory usage over time for long-running scripts
Common Memory Issues
- Circular references: Objects referencing each other prevent GC
- Unbounded caches: Growing dicts/lists without size limits
- Large string concatenation: Creates many intermediate objects
- Global state accumulation: Module-level collections that grow forever
- Unclosed resources: File handles, connections not properly closed
Interview Insight
tracemalloc is the built-in tool for memory analysis — it tracks allocations by source line. Common memory leaks: unbounded caches, circular references, accumulating global state. Use __slots__ on frequently-created classes to reduce per-instance memory by ~40%.
Use Cases
Long-running services — detecting memory leaks that cause OOM crashes
Data processing — optimizing memory usage for large datasets
Cache management — ensuring caches have bounded sizes
Object-heavy applications — reducing per-object memory with __slots__
Production monitoring — tracking memory usage over time
Common Mistakes
Unbounded caches — always set maxsize on caches (lru_cache, custom dicts)
Circular references without weakref — prevents garbage collection
Loading entire files into memory — use generators for large files
Using sys.getsizeof for total size — it is shallow, use recursive size calculation
Not closing resources — always use context managers (with statement) for files and connections