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 thePYTHONTRACEMALLOC
environmentvariable to1
, or by using-X
tracemalloc
command lineoption. Thetracemalloc.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 to25
, or use the-X
tracemalloc=25
command line option.
範例¶
Display the top 10¶
Display the 10 files allocating the most memory:
importtracemalloctracemalloc.start()# ... run your application ...snapshot=tracemalloc.take_snapshot()top_stats=snapshot.statistics('lineno')print("[ Top 10 ]")forstatintop_stats[:10]:print(stat)
Example of output of the Python test suite:
[Top10]<frozenimportlib._bootstrap>:716:size=4855KiB,count=39328,average=126B<frozenimportlib._bootstrap>:284:size=521KiB,count=3199,average=167B/usr/lib/python3.4/collections/__init__.py:368:size=244KiB,count=2315,average=108B/usr/lib/python3.4/unittest/case.py:381:size=185KiB,count=779,average=243B/usr/lib/python3.4/unittest/case.py:402:size=154KiB,count=378,average=416B/usr/lib/python3.4/abc.py:133:size=88.7KiB,count=347,average=262B<frozenimportlib._bootstrap>:1446:size=70.4KiB,count=911,average=79B<frozenimportlib._bootstrap>:1454:size=52.0KiB,count=25,average=2131B<string>:5:size=49.7KiB,count=148,average=344B/usr/lib/python3.4/sysconfig.py:411:size=48.0KiB,count=1,average=48.0KiB
We can see that Python loaded4855KiB
data (bytecode and constants) frommodules and that thecollections
module allocated244KiB
to buildnamedtuple
types.
更多選項請見Snapshot.statistics()
。
Compute differences¶
Take two snapshots and display the differences:
importtracemalloctracemalloc.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 ]")forstatintop_stats[:10]:print(stat)
Example of output before/after running some tests of the Python test suite:
[Top10differences]<frozenimportlib._bootstrap>:716:size=8173KiB(+4428KiB),count=71332(+39369),average=117B/usr/lib/python3.4/linecache.py:127:size=940KiB(+940KiB),count=8106(+8106),average=119B/usr/lib/python3.4/unittest/case.py:571:size=298KiB(+298KiB),count=589(+589),average=519B<frozenimportlib._bootstrap>:284:size=1005KiB(+166KiB),count=7423(+1526),average=139B/usr/lib/python3.4/mimetypes.py:217:size=112KiB(+112KiB),count=1334(+1334),average=86B/usr/lib/python3.4/http/server.py:848:size=96.0KiB(+96.0KiB),count=1(+1),average=96.0KiB/usr/lib/python3.4/inspect.py:1465:size=83.5KiB(+83.5KiB),count=109(+109),average=784B/usr/lib/python3.4/unittest/mock.py:491:size=77.7KiB(+77.7KiB),count=143(+143),average=557B/usr/lib/python3.4/urllib/parse.py:476:size=71.8KiB(+71.8KiB),count=969(+969),average=76B/usr/lib/python3.4/contextlib.py:38:size=67.2KiB(+67.2KiB),count=126(+126),average=546B
We can see that Python has loaded8173KiB
of module data (bytecode andconstants), and that this is4428KiB
more than had been loaded before thetests, when the previous snapshot was taken. Similarly, thelinecache
module has cached940KiB
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 usingtheSnapshot.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:
importtracemalloc# Store 25 framestracemalloc.start(25)# ... run your application ...snapshot=tracemalloc.take_snapshot()top_stats=snapshot.statistics('traceback')# pick the biggest memory blockstat=top_stats[0]print("%s memory blocks:%.1f KiB"%(stat.count,stat.size/1024))forlineinstat.traceback.format():print(line)
Example of output of the Python test suite (traceback limited to 25 frames):
903memoryblocks:870.1KiBFile"<frozen importlib._bootstrap>",line716File"<frozen importlib._bootstrap>",line1036File"<frozen importlib._bootstrap>",line934File"<frozen importlib._bootstrap>",line1068File"<frozen importlib._bootstrap>",line619File"<frozen importlib._bootstrap>",line1581File"<frozen importlib._bootstrap>",line1614File"/usr/lib/python3.4/doctest.py",line101importpdbFile"<frozen importlib._bootstrap>",line284File"<frozen importlib._bootstrap>",line938File"<frozen importlib._bootstrap>",line1068File"<frozen importlib._bootstrap>",line619File"<frozen importlib._bootstrap>",line1581File"<frozen importlib._bootstrap>",line1614File"/usr/lib/python3.4/test/support/__init__.py",line1728importdoctestFile"/usr/lib/python3.4/test/test_pickletools.py",line21support.run_doctest(pickletools)File"/usr/lib/python3.4/test/regrtest.py",line1276test_runner()File"/usr/lib/python3.4/test/regrtest.py",line976display_failure=notverbose)File"/usr/lib/python3.4/test/regrtest.py",line761match_tests=ns.match_tests)File"/usr/lib/python3.4/test/regrtest.py",line1563main()File"/usr/lib/python3.4/test/__main__.py",line3regrtest.main_in_temp_cwd()File"/usr/lib/python3.4/runpy.py",line73exec(code,run_globals)File"/usr/lib/python3.4/runpy.py",line160"__main__",fname,loader,pkg_name)
We can see that the most memory was allocated in theimportlib
module toload data (bytecode and constants) from modules:870.1KiB
. The traceback iswhere theimportlib
loaded data most recently: on theimportpdb
line of thedoctest
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<frozenimportlib._bootstrap>
and<unknown>
files:
importlinecacheimportosimporttracemallocdefdisplay_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)forindex,statinenumerate(top_stats[:limit],1):frame=stat.traceback[0]print("#%s:%s:%s:%.1f KiB"%(index,frame.filename,frame.lineno,stat.size/1024))line=linecache.getline(frame.filename,frame.lineno).strip()ifline:print('%s'%line)other=top_stats[limit:]ifother:size=sum(stat.sizeforstatinother)print("%s other:%.1f KiB"%(len(other),size/1024))total=sum(stat.sizeforstatintop_stats)print("Total allocated size:%.1f KiB"%(total/1024))tracemalloc.start()# ... run your application ...snapshot=tracemalloc.take_snapshot()display_top(snapshot)
Example of output of the Python test suite:
Top10lines#1: Lib/base64.py:414: 419.8 KiB_b85chars2=[(a+b)forain_b85charsforbin_b85chars]#2: Lib/base64.py:306: 419.8 KiB_a85chars2=[(a+b)forain_a85charsforbin_a85chars]#3: collections/__init__.py:368: 293.6 KiBexec(class_definition,namespace)#4: Lib/abc.py:133: 115.2 KiBcls=super().__new__(mcls,name,bases,namespace)#5: unittest/case.py:574: 103.1 KiBtestMethod()#6: Lib/linecache.py:127: 95.4 KiBlines=fp.readlines()#7: urllib/parse.py:476: 71.8 KiBforain_hexdigforbin_hexdig}#8: <string>:5: 62.0 KiB#9: Lib/_weakrefset.py:37: 60.0 KiBself.data=set()#10: Lib/base64.py:142: 59.8 KiB_b32tab2=[a+bforain_b32tabforbin_b32tab]6220other:3602.8KiBTotalallocatedsize:5303.1KiB
更多選項請見Snapshot.statistics()
。
Record the current and peak size of all traced memory blocks¶
The following code computes two sums like0+1+2+...
inefficiently, bycreating a list of those numbers. This list consumes a lot of memorytemporarily. We can useget_traced_memory()
andreset_peak()
toobserve the small memory usage after the sum is computed as well as the peakmemory usage during the computations:
importtracemalloctracemalloc.start()# Example code: compute a sum with a large temporary listlarge_sum=sum(list(range(100000)))first_size,first_peak=tracemalloc.get_traced_memory()tracemalloc.reset_peak()# Example code: compute a sum with a small temporary listsmall_sum=sum(list(range(1000)))second_size,second_peak=tracemalloc.get_traced_memory()print(f"{first_size=},{first_peak=}")print(f"{second_size=},{second_peak=}")
輸出:
first_size=664,first_peak=3592984second_size=804,second_peak=29704
Usingreset_peak()
ensured we could accurately record the peak during thecomputation ofsmall_sum
, even though it is much smaller than the overallpeak size of memory blocks since thestart()
call. Without the call toreset_peak()
,second_peak
would still be the peak from thecomputationlarge_sum
(that is, equal tofirst_peak
). In this case,both peaks are much higher than the final memory usage, and which suggests wecould optimise (by removing the unnecessary call tolist
, and writingsum(range(...))
).
API¶
函式¶
- tracemalloc.get_object_traceback(obj)¶
Get the traceback where the Python objectobj was allocated.Return a
Traceback
instance, orNone
if thetracemalloc
module is not tracing memory allocations or did not trace the allocation ofthe object.另請參閱
gc.get_referrers()
與sys.getsizeof()
函式。
- 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.reset_peak()¶
Set the peak size of memory blocks traced by the
tracemalloc
moduleto the current size.Do nothing if the
tracemalloc
module is not tracing memoryallocations.This function only modifies the recorded peak size, and does not modify orclear any traces, unlike
clear_traces()
. Snapshots taken withtake_snapshot()
before a call toreset_peak()
can bemeaningfully compared to snapshots taken after the call.另請參閱
get_traced_memory()
。在 3.9 版被加入.
- 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.
- tracemalloc.start(nframe:int=1)¶
Start tracing Python memory allocations: install hooks on Python memoryallocators. Collected tracebacks of traces will be limited tonframeframes. By default, a trace of a memory block only stores the most recentframe: the limit is
1
.nframe must be greater or equal to1
.You can still read the original number of total frames that composed thetraceback by looking at the
Traceback.total_nframe
attribute.Storing more than
1
frame is only useful to compute statistics groupedby'traceback'
or to compute cumulative statistics: see theSnapshot.compare_to()
andSnapshot.statistics()
methods.Storing more frames increases the memory and CPU overhead of the
tracemalloc
module. Use theget_tracemalloc_memory()
functionto measure how much memory is used by thetracemalloc
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()
andget_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()
andclear_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 the
tracemalloc
module started to trace memory allocations.Tracebacks of traces are limited to
get_traceback_limit()
frames. Usethenframe parameter of thestart()
function to store more frames.The
tracemalloc
module must be tracing memory allocations to take asnapshot, see thestart()
function.另請參閱
get_object_traceback()
函式。
DomainFilter¶
- classtracemalloc.DomainFilter(inclusive:bool,domain:int)¶
Filter traces of memory blocks by their address space (domain).
在 3.6 版被加入.
- inclusive¶
Ifinclusive is
True
(include), match memory blocks allocatedin the address spacedomain
.Ifinclusive is
False
(exclude), match memory blocks not allocatedin the address spacedomain
.
- domain¶
Address space of a memory block (
int
). Read-only property.
Filter¶
- classtracemalloc.Filter(inclusive:bool,filename_pattern:str,lineno:int=None,all_frames:bool=False,domain:int=None)¶
Filter on traces of memory blocks.
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 版的變更:新增
domain
屬性。- domain¶
Address space of a memory block (
int
orNone
).tracemalloc uses the domain
0
to trace memory allocations made byPython. C extensions can use other domains to trace other resources.
- inclusive¶
Ifinclusive is
True
(include), only match memory blocks allocatedin a file with a name matchingfilename_pattern
at line numberlineno
.Ifinclusive is
False
(exclude), ignore memory blocks allocated ina file with a name matchingfilename_pattern
at line numberlineno
.
- lineno¶
Line number (
int
) of the filter. Iflineno isNone
, the filtermatches any line number.
- filename_pattern¶
Filename pattern of the filter (
str
). Read-only property.
- all_frames¶
Ifall_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 andSnapshot.traceback_limit
attribute.
Frame¶
Snapshot¶
- classtracemalloc.Snapshot¶
Snapshot of traces of memory blocks allocated by Python.
The
take_snapshot()
function creates a snapshot instance.- compare_to(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 bykey_type.See the
Snapshot.statistics()
method forkey_type andcumulativeparameters.The result is sorted from the biggest to the smallest by: absolute valueof
StatisticDiff.size_diff
,StatisticDiff.size
, absolutevalue ofStatisticDiff.count_diff
,Statistic.count
andthen byStatisticDiff.traceback
.
- filter_traces(filters)¶
Create a new
Snapshot
instance with a filteredtraces
sequence,filters is a list ofDomainFilter
andFilter
instances. Iffilters 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 infilters.
- statistics(key_type:str,cumulative:bool=False)¶
Get statistics as a sorted list of
Statistic
instances groupedbykey_type:key_type
描述
'filename'
filename
'lineno'
filename and line number
'traceback'
traceback
Ifcumulative 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 withkey_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¶
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.
Statistic¶
- classtracemalloc.Statistic¶
Statistic on memory allocations.
Snapshot.statistics()
returns a list ofStatistic
instances.See also the
StatisticDiff
class.- count¶
Number of memory blocks (
int
).
- size¶
Total size of memory blocks in bytes (
int
).
StatisticDiff¶
- classtracemalloc.StatisticDiff¶
Statistic difference on memory allocations between an old and a new
Snapshot
instance.Snapshot.compare_to()
returns a list ofStatisticDiff
instances. See also theStatistic
class.- count¶
Number of memory blocks in the new snapshot (
int
):0
ifthe memory blocks have been released in the new snapshot.
- count_diff¶
Difference of number of memory blocks between the old and the newsnapshots (
int
):0
if the memory blocks have been allocated inthe new snapshot.
- size¶
Total size of memory blocks in bytes in the new snapshot (
int
):0
if the memory blocks have been released in the new snapshot.
- size_diff¶
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.
Trace¶
- classtracemalloc.Trace¶
Trace of a memory block.
The
Snapshot.traces
attribute is a sequence ofTrace
instances.在 3.6 版的變更:新增
domain
屬性。- domain¶
Address space of a memory block (
int
). Read-only property.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¶
- classtracemalloc.Traceback¶
Sequence of
Frame
instances sorted from the oldest frame to themost recent frame.A traceback contains at least
1
frame. If thetracemalloc
modulefailed to get a frame, the filename"<unknown>"
at line number0
isused.When a snapshot is taken, tracebacks of traces are limited to
get_traceback_limit()
frames. See thetake_snapshot()
function.The original number of frames of the traceback is stored in theTraceback.total_nframe
attribute. That allows to know if a tracebackhas been truncated by the traceback limit.The
Trace.traceback
attribute is an instance ofTraceback
instance.在 3.7 版的變更:Frames are now sorted from the oldest to the most recent, instead of most recent to oldest.
- total_nframe¶
Total number of frames that composed the traceback before truncation.This attribute can be set to
None
if the information is notavailable.
在 3.9 版的變更:The
Traceback.total_nframe
attribute was added.- format(limit=None,most_recent_first=False)¶
Format the traceback as a list of lines. Use the
linecache
module toretrieve lines from the source code. Iflimit is set, format thelimitmost recent frames iflimit is positive. Otherwise, format theabs(limit)
oldest frames. Ifmost_recent_first isTrue
, the orderof the formatted frames is reversed, returning the most recent frame firstinstead of last.Similar to the
traceback.format_tb()
function, except thatformat()
does not include newlines.範例:
print("Traceback (most recent call first):")forlineintraceback:print(line)
輸出:
Traceback(mostrecentcallfirst):File"test.py",line9obj=Object()File"test.py",line12tb=tracemalloc.get_object_traceback(f())