Profiling with memory_profiler
Swipe to show menu
tracemalloc works from inside your code. memory_profiler takes a different approach – it decorates functions and reports memory usage line by line, showing exactly how much memory each line adds or frees. It is the most readable tool for understanding the memory profile of a specific function.
Installation
pip install memory-profiler
The @profile Decorator
Add @profile to any function and run the script with python -m memory_profiler your_script.py. Each line is annotated with memory usage and the increment from the previous line:
1234567891011121314151617181920212223from memory_profiler import profile @profile def build_sales_report(): # Loading raw sales data sales_records = [ {"region": f"region_{record_id % 10}", "revenue": record_id * 150.0} for record_id in range(100000) ] # Grouping by region region_totals = {} for record in sales_records: region = record["region"] region_totals[region] = region_totals.get(region, 0) + record["revenue"] # Freeing raw data after aggregation del sales_records return region_totals result = build_sales_report() print(f"Regions: {len(result)}")
The del sales_records line shows a clear memory drop – confirming that the cleanup is effective.
The @profile decorator requires running the script via python -m memory_profiler your_script.py to produce line-by-line output. Inside a Jupyter environment it will execute the function normally but skip the memory report. Use memory_usage() for programmatic profiling within notebooks.
Using memory_usage() Programmatically
For use inside a script without the decorator, memory_usage() returns a time series of memory readings while a function runs:
1234567891011121314from memory_profiler import memory_usage import time def process_batch(batch_size): data = list(range(batch_size)) time.sleep(0.1) # Simulating processing time return sum(data) # Sampling memory every 10ms during the function call mem_usage = memory_usage((process_batch, (500000,)), interval=0.01) print(f"Min memory: {min(mem_usage):.1f} MiB") print(f"Max memory: {max(mem_usage):.1f} MiB") print(f"Peak delta: {max(mem_usage) - min(mem_usage):.1f} MiB")
Comparing Two Implementations
memory_profiler makes it easy to compare the memory cost of two approaches side by side:
1234567891011121314from memory_profiler import profile @profile def approach_list(): # Building a full list of computed values return [value ** 2 for value in range(200000)] @profile def approach_generator(): # Consuming a generator without storing results return sum(value ** 2 for value in range(200000)) approach_list() approach_generator()
Running this with python -m memory_profiler shows the memory delta for each line in both functions – approach_list will show a large allocation for the list, while approach_generator stays nearly flat.
tracemalloc vs memory_profiler
Thanks for your feedback!
Ask AI
Ask AI
Ask anything or try one of the suggested questions to begin our chat