Skip to main content

Lib/tracemalloc.py

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py

tracemalloc.py is the pure-Python layer that sits on top of the _tracemalloc C extension. The C layer hooks into PyMem_RawMalloc and friends so that every allocation is tagged with the call stack at the moment it occurred. The Python layer wraps that raw data in typed objects (Frame, Traceback, Statistic, StatisticDiff, Trace, Snapshot) and provides the aggregation and filtering logic that makes the raw numbers readable.

Starting a trace is one line: tracemalloc.start(nframe=1). The optional nframe argument controls how many frames deep each allocation stack is captured. A deeper stack gives more context but uses more memory for the trace data itself. stop() tears down the C hook, and take_snapshot() copies the current allocation table out of the C layer into a Snapshot object so that data is preserved even after the allocator state changes.

Snapshot.statistics(group_by, cumulative=False) is the main analysis method. It groups raw traces by 'filename', 'lineno', or 'traceback', sums sizes within each group, and returns a sorted list of Statistic objects. Two snapshots can be compared with Snapshot.compare_to, which produces StatisticDiff objects showing what grew or shrank between the two points in time. Filter objects narrow which files or line numbers are included in a snapshot before aggregation, keeping reports focused on the code being investigated.

Map

LinesSymbolRolegopy
1-50module header, importsImports from _tracemalloc; constants _UNSET
51-120Frame, TracebackImmutable value types wrapping C-layer stack data
121-200Statistic, StatisticDiffAggregated size/count per group key
201-290Filterinclusive, filename_pattern, lineno, all_frames fields
291-400Snapshottake_snapshot, statistics, compare_to, filter_traces, dump, load
401-460TraceSingle allocation record: traceback, size
461-560module-level APIstart, stop, is_tracing, get_traced_memory, get_object_traceback

Reading

Frame and Traceback (lines 51 to 120)

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py#L51-120

Frame is a two-field named-tuple-like object holding filename and lineno. It implements __repr__, __eq__, __hash__, and __lt__ so that frames sort lexicographically by (filename, lineno). Traceback wraps a tuple of Frame objects and is also hashable and totally ordered. Its format method returns a list of strings suitable for printing, mimicking the output of traceback.format_stack but without source code snippets.

Both types are constructed from raw C-layer tuples in Snapshot._get_traces and are never meant to be created directly by user code.

class Frame:
__slots__ = ("_frame",)
def __init__(self, frame):
if len(frame) != 2:
raise ValueError("...")
self._frame = frame

@property
def filename(self): return self._frame[0]

@property
def lineno(self): return self._frame[1]

Statistic and StatisticDiff (lines 121 to 200)

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py#L121-200

Statistic groups allocation data under a single key (a Traceback, a Frame, or a filename string depending on the group_by argument). Its fields are traceback, size (bytes), and count (number of allocations). It sorts by (-size, -count, traceback) so the heaviest allocations appear first in a list.

StatisticDiff extends that with size_diff and count_diff fields and an old_traceback reference. The compare_to call on Snapshot builds a StatisticDiff for every key that appears in either snapshot, using size_diff=0 for keys present in only one snapshot.

class Statistic:
__slots__ = ("traceback", "size", "count")

def __lt__(self, other):
if self.size != other.size:
return self.size > other.size # descending
...

Filter (lines 201 to 290)

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py#L201-290

A Filter carries a glob-style filename_pattern, an optional lineno, a boolean inclusive flag, and an all_frames flag. When inclusive=True the filter keeps only traces that match; when False it discards matches. all_frames=True makes the filter test every frame in a traceback rather than just the most recent one, which is useful when the allocation happens deep inside a library but you want to restrict by the caller's filename.

Snapshot.filter_traces(filters) applies a list of Filter objects in sequence by calling _filter_traces (a C helper) for each, returning a new Snapshot with the reduced trace set.

class Filter:
def __init__(self, inclusive, filename_pattern,
lineno=None, all_frames=False, domain=None):
self.inclusive = inclusive
self._filename_pattern = os.path.normcase(filename_pattern)
self.lineno = lineno
self.all_frames = all_frames

Snapshot (lines 291 to 400)

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py#L291-400

Snapshot is the central analysis object. take_snapshot() at module level calls _tracemalloc.get_traces() (C), wraps each raw record in a Trace, and freezes the result. statistics(group_by, cumulative=False) groups traces by the chosen key, sums size and count within each group, and returns a sorted list[Statistic]. When cumulative=True, every frame in a traceback contributes to its own group entry, so a callee's allocations are also attributed to all its callers.

dump(filename) and load(filename) use pickle to persist and restore a snapshot, enabling offline analysis of allocations captured on a remote host or in a prior run.

def statistics(self, group_by, cumulative=False):
if group_by not in ("filename", "lineno", "traceback"):
raise ValueError("...")
tracebacks = ...
return Statistic._build(group_by, cumulative, tracebacks)

Module-level API (lines 461 to 560)

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py#L461-560

The module exports a thin Python wrapper around every _tracemalloc function. start(nframe=1) validates that nframe is a positive integer, then delegates to _tracemalloc.start. get_traced_memory() returns a (current_bytes, peak_bytes) tuple since the last clear_traces() call. get_object_traceback(obj) looks up an object by identity in the live trace table and returns its Traceback, or None if tracing was not active when the object was allocated. This last function is especially handy for tracking down reference cycles: you can find the allocation site of an object that has survived longer than expected.

gopy mirror

Not yet ported.