Python tracemalloc: Track Memory

Published on: August 28, 2026
Reading time: 5 minutes
A person typing on a laptop with a Python programming book visible, capturing technology and learning.

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.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Python code on screen representing EnumDict and advanced enumerations
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    EnumDict: Build Custom Enums with Validation

    Learn Python EnumDict for custom EnumType metaclasses, member validation, and safer advanced enumerations.

    Ler mais

    Tempo de leitura: 4 minutos
    11/10/2026
    Server rack representing connection load balancing with Python SO_REUSEPORT_LB
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    SO_REUSEPORT_LB: Balance Connections Across Workers

    Learn Python SO_REUSEPORT_LB to distribute connections across multiple workers with safe testing, portability, and graceful shutdown.

    Ler mais

    Tempo de leitura: 5 minutos
    11/10/2026
    Python asynchronous code on a laptop for inspect.markcoroutinefunction
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    markcoroutinefunction: Detect Async Wrappers

    Learn inspect.markcoroutinefunction in Python to identify async wrappers, integrate frameworks, and avoid incorrect coroutine detection.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Python code for traversing folders and files with Path.walk
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Path.walk: Traverse Directories Safely

    Learn Python Path.walk to traverse directories, filter files, handle errors, and control directory-tree processing safely.

    Ler mais

    Tempo de leitura: 5 minutos
    10/10/2026
    Python process debugging in a terminal with source code
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    pdb -p: Debug Running Python Processes

    Learn how to attach pdb to a running Python process, inspect stacks, and diagnose hangs safely.

    Ler mais

    Tempo de leitura: 6 minutos
    09/10/2026
    Python programming code for exact fractions
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    fractions.from_number: Convert Numbers to Fractions

    Learn Python fractions.from_number for exact rational conversion, float and Decimal handling, approximation, validation, and safe arithmetic.

    Ler mais

    Tempo de leitura: 4 minutos
    09/10/2026