tracemalloc --- 追蹤記憶體配置

在 3.4 版被加入.

原始碼:Lib/tracemalloc.py


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-Xtracemalloc 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-Xtracemalloc=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, thelinecachemodule 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 theimportpdbline 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.clear_traces()

Clear traces of memory blocks allocated by Python.

另請參閱stop()

tracemalloc.get_object_traceback(obj)

Get the traceback where the Python objectobj was allocated.Return aTraceback instance, orNone if thetracemallocmodule 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.

Thetracemalloc module must be tracing memory allocations toget the limit, otherwise an exception is raised.

The limit is set by thestart() function.

tracemalloc.get_traced_memory()

Get the current size and peak size of memory blocks traced by thetracemalloc module as a tuple:(current:int,peak:int).

tracemalloc.reset_peak()

Set the peak size of memory blocks traced by thetracemalloc moduleto the current size.

Do nothing if thetracemalloc module is not tracing memoryallocations.

This function only modifies the recorded peak size, and does not modify orclear any traces, unlikeclear_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 thetracemalloc module used to storetraces of memory blocks.Return anint.

tracemalloc.is_tracing()

True if thetracemalloc module is tracing Python memoryallocations,False otherwise.

另請參閱start()stop() 函式。

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 is1.nframe must be greater or equal to1.

You can still read the original number of total frames that composed thetraceback by looking at theTraceback.total_nframe attribute.

Storing more than1 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 thetracemalloc module. Use theget_tracemalloc_memory() functionto measure how much memory is used by thetracemalloc module.

ThePYTHONTRACEMALLOC environment variable(PYTHONTRACEMALLOC=NFRAME) and the-Xtracemalloc=NFRAMEcommand line option can be used to start tracing at startup.

See alsostop(),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.

Calltake_snapshot() function to take a snapshot of traces beforeclearing them.

See alsostart(),is_tracing() andclear_traces()functions.

tracemalloc.take_snapshot()

Take a snapshot of traces of memory blocks allocated by Python. Return a newSnapshot instance.

The snapshot does not include memory blocks allocated before thetracemalloc module started to trace memory allocations.

Tracebacks of traces are limited toget_traceback_limit() frames. Usethenframe parameter of thestart() function to store more frames.

Thetracemalloc 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 isTrue (include), match memory blocks allocatedin the address spacedomain.

Ifinclusive isFalse (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 thefnmatch.fnmatch() function for the syntax offilename_pattern. The'.pyc' file extension isreplaced with'.py'.

範例:

  • Filter(True,subprocess.__file__) only includes traces of thesubprocess module

  • Filter(False,tracemalloc.__file__) excludes traces of thetracemalloc module

  • Filter(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 domain0 to trace memory allocations made byPython. C extensions can use other domains to trace other resources.

inclusive

Ifinclusive isTrue (include), only match memory blocks allocatedin a file with a name matchingfilename_pattern at line numberlineno.

Ifinclusive isFalse (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 isTrue, 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 is1. See theget_traceback_limit() function andSnapshot.traceback_limitattribute.

Frame

classtracemalloc.Frame

Frame of a traceback.

TheTraceback class is a sequence ofFrame instances.

filename

Filename (str).

lineno

Line number (int).

Snapshot

classtracemalloc.Snapshot

Snapshot of traces of memory blocks allocated by Python.

Thetake_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 ofStatisticDiff instances grouped bykey_type.

See theSnapshot.statistics() method forkey_type andcumulativeparameters.

The result is sorted from the biggest to the smallest by: absolute valueofStatisticDiff.size_diff,StatisticDiff.size, absolutevalue ofStatisticDiff.count_diff,Statistic.count andthen byStatisticDiff.traceback.

dump(filename)

Write the snapshot into a file.

Useload() to reload the snapshot.

filter_traces(filters)

Create a newSnapshot instance with a filteredtracessequence,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.

classmethodload(filename)

Load a snapshot from a file.

另請參閱dump()

statistics(key_type:str,cumulative:bool=False)

Get statistics as a sorted list ofStatistic instances groupedbykey_type:

key_type

描述

'filename'

filename

'lineno'

filename and line number

'traceback'

traceback

Ifcumulative isTrue, 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 oftraces:result of theget_traceback_limit() when the snapshot was taken.

traces

Traces of all memory blocks allocated by Python: sequence ofTrace instances.

The sequence has an undefined order. Use theSnapshot.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 theStatisticDiff class.

count

Number of memory blocks (int).

size

Total size of memory blocks in bytes (int).

traceback

Traceback where the memory block was allocated,Tracebackinstance.

StatisticDiff

classtracemalloc.StatisticDiff

Statistic difference on memory allocations between an old and a newSnapshot instance.

Snapshot.compare_to() returns a list ofStatisticDiffinstances. 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.

traceback

Traceback where the memory blocks were allocated,Tracebackinstance.

Trace

classtracemalloc.Trace

Trace of a memory block.

TheSnapshot.traces attribute is a sequence ofTraceinstances.

在 3.6 版的變更:新增domain 屬性。

domain

Address space of a memory block (int). Read-only property.

tracemalloc uses the domain0 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

Traceback where the memory block was allocated,Tracebackinstance.

Traceback

classtracemalloc.Traceback

Sequence ofFrame instances sorted from the oldest frame to themost recent frame.

A traceback contains at least1 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 toget_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.

TheTrace.traceback attribute is an instance ofTracebackinstance.

在 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 toNone if the information is notavailable.

在 3.9 版的變更:TheTraceback.total_nframe attribute was added.

format(limit=None,most_recent_first=False)

Format the traceback as a list of lines. Use thelinecache 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 thetraceback.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())