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

    Commuters line up at a subway station platform, showcasing public transportation dynamics.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python queue: Communicate Between Threads

    Learn Python queue for thread communication with FIFO, LIFO, priority, backpressure, task tracking, sentinels, and safe shutdown.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A vertical macro shot showcasing metallic socket wrenches in a shallow focus arrangement.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python selectors: Many Sockets

    Learn Python selectors to multiplex sockets, handle partial reads and writes, manage buffers, deadlines, wakeups, and backpressure.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Vivid close-up of a green tree python coiled on a branch in the rainforest.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python contextvars: Async Context

    Learn Python contextvars for task-local context, request IDs, logging, copy_context, thread propagation, and safe token restoration.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    A minimalist June calendar page adorned with red hearts for a romantic touch.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python sched: Schedule Events

    Learn Python sched to schedule events, use priorities, cancel work, create drift-free recurrence, test with fake clocks, and integrate executors.

    Ler mais

    Tempo de leitura: 5 minutos
    28/08/2026
    Stack of colorful sticky notes with a 'To Do' note on top, isolated on white.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python bisect: Keep Lists Sorted

    Learn Python bisect for binary search, ordered insertion, duplicates, key functions, ranges, rankings, and safe concurrent updates.

    Ler mais

    Tempo de leitura: 4 minutos
    28/08/2026
    Close-up of a vibrant yellow python coiled with textured scales in vibrant light.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python heapq: Priority Queues

    Learn Python heapq for priority queues, top-k selection, sorted merges, stable ties, lazy deletion, updates, and backpressure.

    Ler mais

    Tempo de leitura: 4 minutos
    28/08/2026