Skip to main content

Lib/tracemalloc.py

Source:

cpython 3.14 @ ab2d84fe1023/Lib/tracemalloc.py

tracemalloc traces Python memory allocations. It wraps the C-level _tracemalloc module, which hooks into CPython's memory allocator to record a traceback for every live allocation.

Map​

LinesSymbolRole
1-100Frame, TracebackImmutable allocation location objects
101-200Statistic, StatisticDiffPer-file/line byte counts
201-350SnapshotPoint-in-time snapshot of all tracked allocations
351-450Filter, DomainFilterInclude/exclude rules for statistics
451-550start, stop, take_snapshot, get_traced_memoryControl API

Reading​

start and stack depth​

# CPython: Lib/tracemalloc.py:510 start
def start(nframe: int = 1) -> None:
_tracemalloc.start(nframe)

nframe is the number of stack frames to record per allocation. More frames give richer tracebacks but consume more memory and slow allocation.

take_snapshot​

# CPython: Lib/tracemalloc.py:525 take_snapshot
def take_snapshot() -> Snapshot:
if not is_tracing():
raise RuntimeError("the tracemalloc module must be tracing memory "
"allocations to take a snapshot")
traces = _tracemalloc._get_traces()
traceback_limit = _tracemalloc.get_traceback_limit()
return Snapshot(traces, traceback_limit)

_tracemalloc._get_traces() returns a raw list of (domain, size, traceback) tuples from the C layer.

Snapshot.compare_to​

# CPython: Lib/tracemalloc.py:370 Snapshot.compare_to
def compare_to(self, old_snapshot, key_type, cumulative=False):
new_stats = self.statistics(key_type, cumulative)
old_stats = old_snapshot.statistics(key_type, cumulative)
# Build {key: Statistic} dicts and compute diffs
old_dict = {stat.traceback: stat for stat in old_stats}
result = []
for new_stat in new_stats:
old_stat = old_dict.pop(new_stat.traceback, None)
diff = StatisticDiff(new_stat.traceback,
new_stat.size - (old_stat.size if old_stat else 0),
new_stat.count - (old_stat.count if old_stat else 0),
new_stat.size,
new_stat.count)
result.append(diff)
# Add entries that disappeared
for old_stat in old_dict.values():
result.append(StatisticDiff(old_stat.traceback, -old_stat.size, ...))
return sorted(result, key=lambda s: -abs(s.size_diff))

Filter​

# CPython: Lib/tracemalloc.py:246 Filter
class Filter:
def __init__(self, inclusive, filename_pattern,
lineno=None, all_frames=False, domain=None):
self.inclusive = inclusive
self.filename_pattern = filename_pattern
self._filename_pattern = fnmatch.translate(filename_pattern)
...

inclusive=True means "only include allocations from this file". Filters are applied in Snapshot.statistics.

gopy notes​

tracemalloc is rarely needed for the gopy port itself but is used by the CPython test suite (Lib/test/) to detect memory leaks. The _tracemalloc C extension hooks into PyMem_Malloc; gopy's Go allocator would need a parallel hook. For now, a stub that returns empty traces is sufficient to prevent import errors.