The tracemalloc module traces memory allocations made through Python’s memory allocators and records where they occurred. It can report current and peak tracked memory, create snapshots, group allocations by file or line, compare states, and apply filters. It is valuable for investigating memory growth, unbounded caches, accidentally retained structures, and regressions between code versions.
tracemalloc does not measure every byte of resident process memory. Native libraries, external buffers, operating-system memory, GPU allocations, and memory that bypasses traced allocators may be invisible. Combine it with RSS metrics, system tools, and workload knowledge.
Start tracing
Call start() before the code you want to observe.
import tracemalloc
tracemalloc.start()
run_application()
Starting early captures imports and initialization; starting later reduces noise and overhead.
Traceback frame depth
start(nframe) controls how many frames are stored for each allocation.
tracemalloc.start(10)
More frames improve attribution but increase memory and CPU cost.
Check whether tracing is active
is_tracing() reports the global state.
if not tracemalloc.is_tracing():
tracemalloc.start(5)
A library should not start or stop global tracing without documenting its effect on the host application.
Current and peak memory
get_traced_memory() returns current and peak tracked bytes.
current, peak = tracemalloc.get_traced_memory()
print(current, peak)
The peak reveals a temporarily expensive operation even if memory is later released.
Reset the peak
reset_peak() resets the maximum without clearing current allocation traces.
tracemalloc.reset_peak()
run_stage()
current, stage_peak = tracemalloc.get_traced_memory()
This supports phase-by-phase measurement.
Take a snapshot
take_snapshot() captures tracked allocations at one moment.
snapshot = tracemalloc.take_snapshot()
Snapshots consume memory. Do not create them continuously in production without limits.
Statistics by line
statistics("lineno") groups allocations by source line.
for statistic in snapshot.statistics("lineno")[:10]:
print(statistic)
Review total size, allocation count, and average size. Many small allocations can matter as much as one large block.
Group by file or traceback
Use filename to group by file and traceback to separate call paths.
top = snapshot.statistics("traceback")[:5]
for item in top:
print(item.size, item.count)
for frame in item.traceback.format():
print(frame)
Traceback grouping is detailed and can create many groups.
Compare snapshots
A comparison shows growth and shrinkage between two states.
before = tracemalloc.take_snapshot()
run_scenario()
after = tracemalloc.take_snapshot()
for difference in after.compare_to(before, "lineno")[:10]:
print(difference)
Repeat the scenario to separate one-time warm-up from continuing growth.
Warm up before the baseline
Imports, bytecode caches, pools, and lazy initialization create legitimate allocations.
Run a warm-up phase and capture the reference snapshot only after the application reaches a stable state.
Detect repeated growth
for _ in range(5):
run_scenario()
gc.collect()
snapshot = tracemalloc.take_snapshot()
record(snapshot)
Calling gc.collect() can reduce diagnostic noise, but it may not represent normal production behavior.
Filters
Filter and DomainFilter include or exclude traces.
filters = [
tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
tracemalloc.Filter(False, "*/site-packages/*"),
]
filtered = snapshot.filter_traces(filters)
Do not filter dependencies too early; third-party code may be the source of growth.
Inclusive and exclusive filters
An exclusive filter removes matches, while an inclusive filter retains only matching traces.
Document filter patterns so reports remain reproducible.
Allocation tracebacks
Trace APIs can inspect frames recorded for individual blocks.
Aggregated statistics are usually more useful than printing millions of individual traces.
Save and load snapshots
Snapshots can be persisted for later analysis.
snapshot.dump("memory.snap")
loaded = tracemalloc.Snapshot.load("memory.snap")
The file may expose internal paths and source names. Protect it as a diagnostic artifact.
Use linecache in reports
Retrieve source text to enrich output.
import linecache
frame = statistic.traceback[0]
line = linecache.getline(frame.filename, frame.lineno).strip()
See Python linecache.
Enable tracing before imports
Interpreter options and an environment variable can enable tracing before application code starts.
This helps diagnose startup allocations but creates more noise.
Overhead
Recording traceback information for allocations consumes CPU and memory. The cost increases with frame depth.
In production, use short controlled windows, a diagnostic instance, or an operational sampling procedure.
Tracked memory versus RSS
RSS may remain high after Python objects are released because allocators keep arenas for reuse and the operating system manages pages.
A drop in tracked bytes without an RSS drop is not proof of a leak. Analyze trends and allocator behavior.
Native memory
NumPy, image libraries, compression engines, drivers, and C extensions may allocate outside traced domains.
If RSS grows while tracemalloc remains stable, use native profilers and library-specific metrics.
Live objects and references
tracemalloc shows where memory was allocated, not necessarily why an object is still alive.
Combine it with gc, reference inspection, and cache analysis to find ownership.
Leaks versus caches
A cache may grow intentionally, but without a limit it becomes an operational leak.
Inspect maximum size, expiration, key cardinality, and eviction policy.
Threads
Tracing is process-global. Allocations from several threads appear in the same snapshots.
Synchronize diagnostic scenarios so snapshots compare equivalent workload phases.
Processes
Each process has an independent tracemalloc state.
In multiprocessing systems, collect snapshots or metrics per worker and aggregate externally. Do not confuse one worker’s memory with total service memory.
Regression tests
A test can repeat a scenario and verify that net growth stays within a tolerance.
Avoid overly rigid thresholds because Python versions, platforms, and imports change exact numbers. Test trends with margins.
Measure one function
def measure(function, *args, **kwargs):
tracemalloc.start(10)
try:
tracemalloc.reset_peak()
result = function(*args, **kwargs)
current, peak = tracemalloc.get_traced_memory()
return result, current, peak
finally:
tracemalloc.stop()
Do not stop tracing that another component owns. Coordinate global state.
clear_traces
clear_traces() removes recorded traces without changing live objects.
Use it to begin a fresh diagnostic phase, understanding that earlier attribution is lost.
stop
stop() disables tracing and clears internal trace state according to the version’s semantics.
Snapshot objects already created can still be analyzed independently.
Useful reports
Include file, line, source text, size, difference, count, and average. Show human-readable units but preserve raw bytes for calculations.
Highlight the largest growth instead of dumping thousands of entries.
Security and privacy
Paths and source lines may reveal customer names, internal directories, and proprietary logic.
Redact diagnostic output before attaching it to public tickets.
Observability
tracemalloc is primarily a diagnostic tool rather than a high-frequency continuous metric.
Monitor RSS, object counts, and cache metrics continuously, then activate snapshots when trends indicate a problem.
Testing
Test a stable scenario, intentional growth, object release, bounded caches, several threads, and separate workers.
Control warm-up, use deterministic input, and repeat runs to reduce noise.
Common mistakes
Common failures include confusing tracked memory with RSS, taking a baseline before warm-up, using only one snapshot, filtering dependencies too early, ignoring native allocations, storing too many frames in production, and assuming every increase is a leak.
Conclusion
tracemalloc shows where Python allocates memory and how that profile changes over time. Use comparable snapshots, documented filters, per-stage peaks, and repeated scenarios.
Combine results with RSS, garbage collection, and native-library metrics. Consult the official tracemalloc documentation, Python linecache, and the guide to finding Python memory leaks.







