Tracemalloc#
Tracemalloc is a package that monitors memory allocation in python.
Statistics#
The tracemalloc
stores memory allocation information in special Statistic
objects. It has 3 fileds:
traceback
: object that refers to the line that allocated memory.size
: size in bytes of the memory allocated.count
: the number of blocks that have been allocated. A block is a contiguous piece of memory that is allocated separately from others.
The following cell takes the random allocation record that we’ll use as an example and shows representation of the statistics object as a string.
import tracemalloc
tracemalloc.start()
ans = tracemalloc.take_snapshot().statistics('lineno')
stat_trace = ans[0]
print(stat_trace)
/usr/local/lib/python3.13/linecache.py:172: size=279 KiB, count=3002, average=95 B
The next code shows the type of the object we’re dealing with.
type(stat_trace)
tracemalloc.Statistic
Next three cells shows count
, size
and traceback
attibutes of the statistic.
stat_trace.count
3002
stat_trace.size
285727
stat_trace.traceback
<Traceback (<Frame filename='/usr/local/lib/python3.13/linecache.py' lineno=172>,)>
Peak#
The tracemalloc.get_traced_memory
function returns the current amount of used memory and the memory usage peak. For more details, check the tracemalloc.get_traced_memory
section of the official documentation.
The following example creates a script that calls some_function
that just allocates memory for res = [0]
and then exits. This causes the garbage collector to immediately take all objects allocated by some_function
.
It then calls tracemalloc.get_traced_memory
and prints the outputs: current and peak memory usage.
%%writefile /tmp/tracemalloc_files.py
import tracemalloc
def some_function():
res = [0]
tracemalloc.start()
some_function()
curr, peak = tracemalloc.get_traced_memory()
print(curr, peak)
Overwriting /tmp/tracemalloc_files.py
!python3 /tmp/tracemalloc_files.py
0 8
The result is that the currently allocated memory is empty after calling tracemalloc.start()
. However, when the function was executed, the memory consumption peaked at 8 bytes.
Monitoring scope#
This section explains which actions can be added to the tracemalloc
results and how to work with them.
Operations that was performed before the tracemalloc.start()
call obviously are not included in the tracemalloc
outputs. Therefore, all monitoring begins with the tracemalloc.start()
call.
The code represented in the following cell attempts to create a two lists: one before the tracemalloc.start()
call and one after.
%%writefile /tmp/tracemalloc_scope.py
import tracemalloc
lst1 = [20]
tracemalloc.start()
lst2 = [30, 20]
ans = tracemalloc.take_snapshot().statistics("lineno")
for v in ans:
print(v)
Overwriting /tmp/tracemalloc_scope.py
!python3 /tmp/tracemalloc_scope.py
/tmp/tracemalloc_scope.py:7: size=16 B, count=1, average=16 B
There is only one allocation mentioned in traces, and it belongs to the lst2 = [30, 20]
assignment.
Restart#
Double call of the tracemalloc.start()
does nothing.
It doesn’t restart tracemalloc
with reset of all traces, even through that might seem intuitive.
The following cell shows the code that declares lists both after the corresponding tracemalloc.start()
call.
%%writefile /tmp/tracemalloc_scope.py
import tracemalloc
tracemalloc.start()
lst1 = [20]
tracemalloc.start()
lst2 = [30, 20]
ans = tracemalloc.take_snapshot().statistics("lineno")
for v in ans:
print(v)
Overwriting /tmp/tracemalloc_scope.py
!python3 /tmp/tracemalloc_scope.py
/tmp/tracemalloc_scope.py:4: size=408 B, count=2, average=204 B
/tmp/tracemalloc_scope.py:7: size=16 B, count=1, average=16 B
The resutls include allocations associated with creating lists. Therefore, the second tracemalloc.start()
call does not clear the accumulated traces.
Clear traces#
If, at any point, you need to ignore traces that have appeared since the tracemalloc.start
call, you should use tracemalloc.clear_traces()
.
The following cell causes python to allocate memory before and after tracemalloc.clear_traces()
.
%%writefile /tmp/tracemalloc_scope.py
import tracemalloc
tracemalloc.start()
lst1 = [20]
tracemalloc.clear_traces()
lst2 = [30, 20]
ans = tracemalloc.take_snapshot().statistics("lineno")
for v in ans:
print(v)
Overwriting /tmp/tracemalloc_scope.py
!python3 /tmp/tracemalloc_scope.py
/tmp/tracemalloc_scope.py:7: size=16 B, count=1, average=16 B
Consequently, there is only the trace corresponding to the creation of the second list.