tracemalloc —- 跟踪内存分配
3.4 新版功能.
The tracemalloc module is a debug tool to trace memory blocks allocated byPython. It provides the following information:
Traceback where an object was allocated
Statistics on allocated memory blocks per filename and per line number:total size, number and average size of allocated memory blocks
Compute the differences between two snapshots to detect memory leaks
To trace most memory blocks allocated by Python, the module should be startedas early as possible by setting the PYTHONTRACEMALLOC
environmentvariable to 1
, or by using -X
tracemalloc
command lineoption. The tracemalloc.start()
function can be called at runtime tostart tracing Python memory allocations.
By default, a trace of an allocated memory block only stores the most recentframe (1 frame). To store 25 frames at startup: set thePYTHONTRACEMALLOC
environment variable to 25
, or use the-X
tracemalloc=25
command line option.
例子
显示前10项
显示内存分配最多的10个文件:
- import tracemalloc
- tracemalloc.start()
- # ... run your application ...
- snapshot = tracemalloc.take_snapshot()
- top_stats = snapshot.statistics('lineno')
- print("[ Top 10 ]")
- for stat in top_stats[:10]:
- print(stat)
Python测试套件的输出示例:
- [ Top 10 ]
- <frozen importlib._bootstrap>:716: size=4855 KiB, count=39328, average=126 B
- <frozen importlib._bootstrap>:284: size=521 KiB, count=3199, average=167 B
- /usr/lib/python3.4/collections/__init__.py:368: size=244 KiB, count=2315, average=108 B
- /usr/lib/python3.4/unittest/case.py:381: size=185 KiB, count=779, average=243 B
- /usr/lib/python3.4/unittest/case.py:402: size=154 KiB, count=378, average=416 B
- /usr/lib/python3.4/abc.py:133: size=88.7 KiB, count=347, average=262 B
- <frozen importlib._bootstrap>:1446: size=70.4 KiB, count=911, average=79 B
- <frozen importlib._bootstrap>:1454: size=52.0 KiB, count=25, average=2131 B
- <string>:5: size=49.7 KiB, count=148, average=344 B
- /usr/lib/python3.4/sysconfig.py:411: size=48.0 KiB, count=1, average=48.0 KiB
We can see that Python loaded 4855 KiB
data (bytecode and constants) frommodules and that the collections
module allocated 244 KiB
to buildnamedtuple
types.
See Snapshot.statistics()
for more options.
计算差异
获取两个快照并显示差异:
- import tracemalloc
- tracemalloc.start()
- # ... start your application ...
- snapshot1 = tracemalloc.take_snapshot()
- # ... call the function leaking memory ...
- snapshot2 = tracemalloc.take_snapshot()
- top_stats = snapshot2.compare_to(snapshot1, 'lineno')
- print("[ Top 10 differences ]")
- for stat in top_stats[:10]:
- print(stat)
Example of output before/after running some tests of the Python test suite:
- [ Top 10 differences ]
- <frozen importlib._bootstrap>:716: size=8173 KiB (+4428 KiB), count=71332 (+39369), average=117 B
- /usr/lib/python3.4/linecache.py:127: size=940 KiB (+940 KiB), count=8106 (+8106), average=119 B
- /usr/lib/python3.4/unittest/case.py:571: size=298 KiB (+298 KiB), count=589 (+589), average=519 B
- <frozen importlib._bootstrap>:284: size=1005 KiB (+166 KiB), count=7423 (+1526), average=139 B
- /usr/lib/python3.4/mimetypes.py:217: size=112 KiB (+112 KiB), count=1334 (+1334), average=86 B
- /usr/lib/python3.4/http/server.py:848: size=96.0 KiB (+96.0 KiB), count=1 (+1), average=96.0 KiB
- /usr/lib/python3.4/inspect.py:1465: size=83.5 KiB (+83.5 KiB), count=109 (+109), average=784 B
- /usr/lib/python3.4/unittest/mock.py:491: size=77.7 KiB (+77.7 KiB), count=143 (+143), average=557 B
- /usr/lib/python3.4/urllib/parse.py:476: size=71.8 KiB (+71.8 KiB), count=969 (+969), average=76 B
- /usr/lib/python3.4/contextlib.py:38: size=67.2 KiB (+67.2 KiB), count=126 (+126), average=546 B
We can see that Python has loaded 8173 KiB
of module data (bytecode andconstants), and that this is 4428 KiB
more than had been loaded before thetests, when the previous snapshot was taken. Similarly, the linecache
module has cached 940 KiB
of Python source code to format tracebacks, allof it since the previous snapshot.
If the system has little free memory, snapshots can be written on disk usingthe Snapshot.dump()
method to analyze the snapshot offline. Then use theSnapshot.load()
method reload the snapshot.
Get the traceback of a memory block
Code to display the traceback of the biggest memory block:
- import tracemalloc
- # Store 25 frames
- tracemalloc.start(25)
- # ... run your application ...
- snapshot = tracemalloc.take_snapshot()
- top_stats = snapshot.statistics('traceback')
- # pick the biggest memory block
- stat = top_stats[0]
- print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))
- for line in stat.traceback.format():
- print(line)
Example of output of the Python test suite (traceback limited to 25 frames):
- 903 memory blocks: 870.1 KiB
- File "<frozen importlib._bootstrap>", line 716
- File "<frozen importlib._bootstrap>", line 1036
- File "<frozen importlib._bootstrap>", line 934
- File "<frozen importlib._bootstrap>", line 1068
- File "<frozen importlib._bootstrap>", line 619
- File "<frozen importlib._bootstrap>", line 1581
- File "<frozen importlib._bootstrap>", line 1614
- File "/usr/lib/python3.4/doctest.py", line 101
- import pdb
- File "<frozen importlib._bootstrap>", line 284
- File "<frozen importlib._bootstrap>", line 938
- File "<frozen importlib._bootstrap>", line 1068
- File "<frozen importlib._bootstrap>", line 619
- File "<frozen importlib._bootstrap>", line 1581
- File "<frozen importlib._bootstrap>", line 1614
- File "/usr/lib/python3.4/test/support/__init__.py", line 1728
- import doctest
- File "/usr/lib/python3.4/test/test_pickletools.py", line 21
- support.run_doctest(pickletools)
- File "/usr/lib/python3.4/test/regrtest.py", line 1276
- test_runner()
- File "/usr/lib/python3.4/test/regrtest.py", line 976
- display_failure=not verbose)
- File "/usr/lib/python3.4/test/regrtest.py", line 761
- match_tests=ns.match_tests)
- File "/usr/lib/python3.4/test/regrtest.py", line 1563
- main()
- File "/usr/lib/python3.4/test/__main__.py", line 3
- regrtest.main_in_temp_cwd()
- File "/usr/lib/python3.4/runpy.py", line 73
- exec(code, run_globals)
- File "/usr/lib/python3.4/runpy.py", line 160
- "__main__", fname, loader, pkg_name)
We can see that the most memory was allocated in the importlib
module toload data (bytecode and constants) from modules: 870.1 KiB
. The traceback iswhere the importlib
loaded data most recently: on the import pdb
line of the doctest
module. The traceback may change if a new module isloaded.
Pretty top
Code to display the 10 lines allocating the most memory with a pretty output,ignoring <frozen importlib._bootstrap>
and <unknown>
files:
- import linecache
- import os
- import tracemalloc
- def display_top(snapshot, key_type='lineno', limit=10):
- snapshot = snapshot.filter_traces((
- tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
- tracemalloc.Filter(False, "<unknown>"),
- ))
- top_stats = snapshot.statistics(key_type)
- print("Top %s lines" % limit)
- for index, stat in enumerate(top_stats[:limit], 1):
- frame = stat.traceback[0]
- # replace "/path/to/module/file.py" with "module/file.py"
- filename = os.sep.join(frame.filename.split(os.sep)[-2:])
- print("#%s: %s:%s: %.1f KiB"
- % (index, filename, frame.lineno, stat.size / 1024))
- line = linecache.getline(frame.filename, frame.lineno).strip()
- if line:
- print(' %s' % line)
- other = top_stats[limit:]
- if other:
- size = sum(stat.size for stat in other)
- print("%s other: %.1f KiB" % (len(other), size / 1024))
- total = sum(stat.size for stat in top_stats)
- print("Total allocated size: %.1f KiB" % (total / 1024))
- tracemalloc.start()
- # ... run your application ...
- snapshot = tracemalloc.take_snapshot()
- display_top(snapshot)
Python测试套件的输出示例:
- Top 10 lines
- #1: Lib/base64.py:414: 419.8 KiB
- _b85chars2 = [(a + b) for a in _b85chars for b in _b85chars]
- #2: Lib/base64.py:306: 419.8 KiB
- _a85chars2 = [(a + b) for a in _a85chars for b in _a85chars]
- #3: collections/__init__.py:368: 293.6 KiB
- exec(class_definition, namespace)
- #4: Lib/abc.py:133: 115.2 KiB
- cls = super().__new__(mcls, name, bases, namespace)
- #5: unittest/case.py:574: 103.1 KiB
- testMethod()
- #6: Lib/linecache.py:127: 95.4 KiB
- lines = fp.readlines()
- #7: urllib/parse.py:476: 71.8 KiB
- for a in _hexdig for b in _hexdig}
- #8: <string>:5: 62.0 KiB
- #9: Lib/_weakrefset.py:37: 60.0 KiB
- self.data = set()
- #10: Lib/base64.py:142: 59.8 KiB
- _b32tab2 = [a + b for a in _b32tab for b in _b32tab]
- 6220 other: 3602.8 KiB
- Total allocated size: 5303.1 KiB
See Snapshot.statistics()
for more options.
API
函数
See also stop()
.
tracemalloc.
getobject_traceback
(_obj)- Get the traceback where the Python object obj was allocated.Return a
Traceback
instance, orNone
if thetracemalloc
module is not tracing memory allocations or did not trace the allocation ofthe object.
See also gc.get_referrers()
and sys.getsizeof()
functions.
tracemalloc.
get_traceback_limit
()- Get the maximum number of frames stored in the traceback of a trace.
The tracemalloc
module must be tracing memory allocations toget the limit, otherwise an exception is raised.
The limit is set by the start()
function.
tracemalloc.
get_traced_memory
()- Get the current size and peak size of memory blocks traced by the
tracemalloc
module as a tuple:(current: int, peak: int)
.
tracemalloc.
get_tracemalloc_memory
()- Get the memory usage in bytes of the
tracemalloc
module used to storetraces of memory blocks.Return anint
.
tracemalloc.
is_tracing
()True
if thetracemalloc
module is tracing Python memoryallocations,False
otherwise.
See also start()
and stop()
functions.
tracemalloc.
start
(nframe: int=1)- Start tracing Python memory allocations: install hooks on Python memoryallocators. Collected tracebacks of traces will be limited to nframe_frames. By default, a trace of a memory block only stores the most recentframe: the limit is
1
. _nframe must be greater or equal to1
.
Storing more than 1
frame is only useful to compute statistics groupedby 'traceback'
or to compute cumulative statistics: see theSnapshot.compare_to()
and Snapshot.statistics()
methods.
Storing more frames increases the memory and CPU overhead of thetracemalloc
module. Use the get_tracemalloc_memory()
functionto measure how much memory is used by the tracemalloc
module.
The PYTHONTRACEMALLOC
environment variable(PYTHONTRACEMALLOC=NFRAME
) and the -X
tracemalloc=NFRAME
command line option can be used to start tracing at startup.
See also stop()
, is_tracing()
and get_traceback_limit()
functions.
tracemalloc.
stop
()- Stop tracing Python memory allocations: uninstall hooks on Python memoryallocators. Also clears all previously collected traces of memory blocksallocated by Python.
Call take_snapshot()
function to take a snapshot of traces beforeclearing them.
See also start()
, is_tracing()
and clear_traces()
functions.
tracemalloc.
take_snapshot
()- Take a snapshot of traces of memory blocks allocated by Python. Return a new
Snapshot
instance.
The snapshot does not include memory blocks allocated before thetracemalloc
module started to trace memory allocations.
Tracebacks of traces are limited to get_traceback_limit()
frames. Usethe nframe parameter of the start()
function to store more frames.
The tracemalloc
module must be tracing memory allocations to take asnapshot, see the start()
function.
See also the get_object_traceback()
function.
域过滤器
- class
tracemalloc.
DomainFilter
(inclusive: bool, domain: int) - Filter traces of memory blocks by their address space (domain).
3.6 新版功能.
inclusive
- If inclusive is
True
(include), match memory blocks allocatedin the address spacedomain
.
If inclusive is False
(exclude), match memory blocks not allocatedin the address space domain
.
过滤器
- class
tracemalloc.
Filter
(inclusive: bool, filename_pattern: str, lineno: int=None, all_frames: bool=False, domain: int=None) - 对内存块的跟踪进行筛选。
See the fnmatch.fnmatch()
function for the syntax offilename_pattern. The '.pyc'
file extension isreplaced with '.py'
.
示例:
Filter(True, subprocess.file)
only includes traces of thesubprocess
moduleFilter(False, tracemalloc.file)
excludes traces of thetracemalloc
moduleFilter(False, "<unknown>")
excludes empty tracebacks
在 3.5 版更改: The '.pyo'
file extension is no longer replaced with '.py'
.
在 3.6 版更改: Added the domain
attribute.
tracemalloc uses the domain 0
to trace memory allocations made byPython. C extensions can use other domains to trace other resources.
inclusive
- If inclusive is
True
(include), only match memory blocks allocatedin a file with a name matchingfilename_pattern
at line numberlineno
.
If inclusive is False
(exclude), ignore memory blocks allocated ina file with a name matching filename_pattern
at line numberlineno
.
lineno
Line number (
int
) of the filter. If lineno isNone
, the filtermatches any line number.Filename pattern of the filter (
str
). Read-only property.- If all_frames is
True
, all frames of the traceback are checked. Ifall_frames isFalse
, only the most recent frame is checked.
This attribute has no effect if the traceback limit is 1
. See theget_traceback_limit()
function and Snapshot.traceback_limit
attribute.
Frame
The Traceback
class is a sequence of Frame
instances.
快照
The take_snapshot()
function creates a snapshot instance.
compareto
(_old_snapshot: Snapshot, key_type: str, cumulative: bool=False)- Compute the differences with an old snapshot. Get statistics as a sortedlist of
StatisticDiff
instances grouped by key_type.
See the Snapshot.statistics()
method for key_type and _cumulative_parameters.
The result is sorted from the biggest to the smallest by: absolute valueof StatisticDiff.size_diff
, StatisticDiff.size
, absolutevalue of StatisticDiff.count_diff
, Statistic.count
andthen by StatisticDiff.traceback
.
使用 load()
重载快照。
filtertraces
(_filters)- Create a new
Snapshot
instance with a filteredtraces
sequence, filters is a list ofDomainFilter
andFilter
instances. If filters is an empty list, return a newSnapshot
instance with a copy of the traces.
All inclusive filters are applied at once, a trace is ignored if noinclusive filters match it. A trace is ignored if at least one exclusivefilter matches it.
在 3.6 版更改: DomainFilter
instances are now also accepted in filters.
另见 dump()
.
statistics
(key_type: str, cumulative: bool=False)- 获取
Statistic
信息列表,按 key_type 分组排序:
key_type
描述
'filename'
filename
'lineno'
文件名和行号
'traceback'
回溯
If cumulative is True
, cumulate size and count of memory blocks ofall frames of the traceback of a trace, not only the most recent frame.The cumulative mode can only be used with key_type equals to'filename'
and 'lineno'
.
The result is sorted from the biggest to the smallest by:Statistic.size
, Statistic.count
and then byStatistic.traceback
.
traceback_limit
Maximum number of frames stored in the traceback of
traces
:result of theget_traceback_limit()
when the snapshot was taken.- Traces of all memory blocks allocated by Python: sequence of
Trace
instances.
The sequence has an undefined order. Use the Snapshot.statistics()
method to get a sorted list of statistics.
统计
Snapshot.statistics()
返回 Statistic
实例的列表。.
参见 StatisticDiff
类。
count
内存块数(
整形
)。Total size of memory blocks in bytes (
int
).- Traceback where the memory block was allocated,
Traceback
instance.
StatisticDiff
- class
tracemalloc.
StatisticDiff
- Statistic difference on memory allocations between an old and a new
Snapshot
instance.
Snapshot.compare_to()
returns a list of StatisticDiff
instances. See also the Statistic
class.
count
Number of memory blocks in the new snapshot (
int
):0
ifthe memory blocks have been released in the new snapshot.Difference of number of memory blocks between the old and the newsnapshots (
int
):0
if the memory blocks have been allocated inthe new snapshot.Total size of memory blocks in bytes in the new snapshot (
int
):0
if the memory blocks have been released in the new snapshot.Difference of total size of memory blocks in bytes between the old andthe new snapshots (
int
):0
if the memory blocks have beenallocated in the new snapshot.- Traceback where the memory blocks were allocated,
Traceback
instance.
跟踪
The Snapshot.traces
attribute is a sequence of Trace
instances.
在 3.6 版更改: Added the domain
attribute.
tracemalloc uses the domain 0
to trace memory allocations made byPython. C extensions can use other domains to trace other resources.
size
Size of the memory block in bytes (
int
).- Traceback where the memory block was allocated,
Traceback
instance.
回溯
- class
tracemalloc.
Traceback
- Sequence of
Frame
instances sorted from the oldest frame to themost recent frame.
A traceback contains at least 1
frame. If the tracemalloc
modulefailed to get a frame, the filename "<unknown>"
at line number 0
isused.
When a snapshot is taken, tracebacks of traces are limited toget_traceback_limit()
frames. See the take_snapshot()
function.
The Trace.traceback
attribute is an instance of Traceback
instance.
在 3.7 版更改: Frames are now sorted from the oldest to the most recent, instead of most recent to oldest.
format
(limit=None, most_recent_first=False)- Format the traceback as a list of lines with newlines. Use the
linecache
module to retrieve lines from the source code.If limit is set, format the limit most recent frames if limit_is positive. Otherwise, format theabs(limit)
oldest frames.If _most_recent_first isTrue
, the order of the formatted framesis reversed, returning the most recent frame first instead of last.
Similar to the traceback.format_tb()
function, except thatformat()
does not include newlines.
示例:
- print("Traceback (most recent call first):")
- for line in traceback:
- print(line)
输出:
- Traceback (most recent call first):
- File "test.py", line 9
- obj = Object()
- File "test.py", line 12
- tb = tracemalloc.get_object_traceback(f())