tracemalloc
— Spåra minnesallokeringar¶
Tillagd i version 3.4.
Källkod: Lib/tracemalloc.py
Modulen tracemalloc är ett felsökningsverktyg för att spåra minnesblock som allokerats av Python. Den ger följande information:
Traceback där ett objekt allokerades
Statistik över allokerade minnesblock per filnamn och radnummer: total storlek, antal och genomsnittlig storlek på allokerade minnesblock
Beräkna skillnaderna mellan två ögonblicksbilder för att upptäcka minnesläckor
För att spåra de flesta minnesblock som allokeras av Python bör modulen startas så tidigt som möjligt genom att ställa in miljövariabeln PYTHONTRACEMALLOC
till 1
, eller genom att använda kommandoradsalternativet -X
tracemalloc
. Funktionen tracemalloc.start()
kan anropas vid körning för att börja spåra Python-minnesallokeringar.
Som standard lagrar en spårning av ett allokerat minnesblock endast den senaste bilden (1 bild). För att lagra 25 bildrutor vid start: sätt miljövariabeln PYTHONTRACEMALLOC
till 25
, eller använd kommandoradsalternativet -X
tracemalloc=25
.
Exempel¶
Visa de 10 bästa¶
Visa de 10 filer som allokerar mest minne:
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)
Exempel på utdata från Python-testsviten:
[ 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
Vi kan se att Python laddade 4855 KiB
data (bytekod och konstanter) från moduler och att modulen collections
allokerade 244 KiB
för att bygga namedtuple
-typer.
Se Snapshot.statistics()
för fler alternativ.
Beräkna skillnader¶
Ta två ögonblicksbilder och visa skillnaderna:
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)
Exempel på utdata före/efter körning av några tester i Python-testsviten:
[ 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
Vi kan se att Python har laddat 8173 KiB
moduldata (bytekod och konstanter), och att detta är 4428 KiB
mer än vad som hade laddats före testerna, när den föregående ögonblicksbilden togs. På samma sätt har modulen linecache
cachat 940 KiB
Python-källkod för att formatera spårningar, allt sedan den föregående ögonblicksbilden.
Om systemet har lite ledigt minne kan ögonblicksbilder skrivas på disk med hjälp av metoden Snapshot.dump()
för att analysera ögonblicksbilden offline. Använd sedan metoden Snapshot.load()
för att ladda om ögonblicksbilden.
Hämta spårningen av ett minnesblock¶
Kod för att visa spårningen av det största minnesblocket:
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)
Exempel på utdata från Python-testsviten (traceback begränsad till 25 ramar):
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)
Vi kan se att det mesta minnet allokerades i modulen importlib
för att ladda data (bytecode och konstanter) från moduler: 870,1 KiB
. Spårningen är där importlib
laddade data senast: på import pdb
-raden i doctest
-modulen. Spårningen kan ändras om en ny modul laddas.
Snygg topp¶
Kod för att visa de 10 rader som allokerar mest minne med en vacker utdata, ignorerar filerna <frozen importlib._bootstrap>
och <unknown>
:
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]
print("#%s: %s:%s: %.1f KiB"
% (index, frame.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)
Exempel på utdata från Python-testsviten:
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
Se Snapshot.statistics()
för fler alternativ.
Registrera den aktuella och maximala storleken på alla spårade minnesblock¶
Följande kod beräknar två summor som 0 + 1 + 2 + ...
ineffektivt genom att skapa en lista med dessa tal. Denna lista förbrukar mycket minne temporärt. Vi kan använda get_traced_memory()
och reset_peak()
för att observera den lilla minnesanvändningen efter att summan har beräknats samt den maximala minnesanvändningen under beräkningarna:
import tracemalloc
tracemalloc.start()
# Example code: compute a sum with a large temporary list
large_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 list
small_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=}")
Utdata:
first_size=664, first_peak=3592984
second_size=804, second_peak=29704
Genom att använda reset_peak()
säkerställde vi att vi korrekt kunde registrera toppen under beräkningen av small_sum
, även om den är mycket mindre än den totala toppstorleken för minnesblock sedan anropet till start()
. Utan anropet till reset_peak()
skulle second_peak
fortfarande vara toppen från beräkningen av large_sum
(dvs. lika med first_peak
). I det här fallet är båda topparna mycket högre än den slutliga minnesanvändningen, vilket tyder på att vi kan optimera (genom att ta bort det onödiga anropet till list
och skriva sum(range(...))
).
API¶
Funktioner¶
- tracemalloc.get_object_traceback(obj)¶
Hämta spårningen där Python-objektet obj allokerades. Returnerar en
Traceback
-instans, ellerNone
omtracemalloc
-modulen inte spårar minnesallokeringar eller inte spårade allokeringen av objektet.Se även funktionerna
gc.get_referrers()
ochsys.getsizeof()
.
- tracemalloc.get_traceback_limit()¶
Hämta det maximala antalet bildrutor som lagras i traceback för en trace.
Modulen
tracemalloc
måste spåra minnesallokeringar för att få fram gränsen, annars uppstår ett undantag.Gränsen sätts av funktionen
start()
.
- tracemalloc.get_traced_memory()¶
Hämta den aktuella storleken och toppstorleken på minnesblock som spåras av modulen
tracemalloc
som en tupel:(current: int, peak: int)
.
- tracemalloc.reset_peak()¶
Ställ in den maximala storleken på minnesblock som spåras av modulen
tracemalloc
till den aktuella storleken.Gör ingenting om modulen
tracemalloc
inte spårar minnesallokeringar.Denna funktion ändrar bara den registrerade toppstorleken och ändrar eller rensar inte några spår, till skillnad från
clear_traces()
. Ögonblicksbilder som tagits medtake_snapshot()
före ett anrop tillreset_peak()
kan på ett meningsfullt sätt jämföras med ögonblicksbilder som tagits efter anropet.Se även
get_traced_memory()
.Tillagd i version 3.9.
- tracemalloc.get_tracemalloc_memory()¶
Hämtar minnesanvändningen i byte för
tracemalloc
-modulen som används för att lagra spår av minnesblock. Returnerar enint
.
- tracemalloc.is_tracing()¶
True
om modulentracemalloc`
spårar Python-minnesallokeringar,False
annars.
- tracemalloc.start(nframe: int = 1)¶
Börja spåra Python-minnesallokeringar: installera hooks på Python-minnesallokatorer. Insamlade spårningar av spårningar kommer att begränsas till nframe-ramar. Som standard lagrar en spårning av ett minnesblock endast den senaste ramen: gränsen är
1
. nframe måste vara större än eller lika med1
.Du kan fortfarande läsa det ursprungliga antalet totala bildrutor som utgjorde traceback genom att titta på attributet
Traceback.total_nframe
.Att lagra mer än
1
ram är endast användbart för att beräkna statistik grupperad efter'traceback'
eller för att beräkna kumulativ statistik: se metodernaSnapshot.compare_to()
ochSnapshot.statistics()
.Om du lagrar fler ramar ökar minnes- och processorkostnaden för modulen
tracemalloc
. Använd funktionenget_tracemalloc_memory()
för att mäta hur mycket minne som används av modulentracemalloc
.Miljövariabeln
PYTHONTRACEMALLOC
(PYTHONTRACEMALLOC=NFRAME
) och kommandoradsalternativet-X
tracemalloc=NFRAME
kan användas för att starta spårning vid uppstart.Se även funktionerna
stop()
,is_tracing()
ochget_traceback_limit()
.
- tracemalloc.stop()¶
Sluta spåra Python-minnesallokeringar: avinstallera hooks på Python-minnesallokatorer. Rensar även alla tidigare insamlade spår av minnesblock som allokerats av Python.
Anropa funktionen
take_snapshot()
för att ta en ögonblicksbild av spåren innan de rensas.Se även funktionerna
start()
,is_tracing()
ochclear_traces()
.
- tracemalloc.take_snapshot()¶
Ta en ögonblicksbild av spår av minnesblock som allokerats av Python. Returnerar en ny
Snapshot
-instans.Ögonblicksbilden innehåller inte minnesblock som allokerats innan modulen
tracemalloc
började spåra minnesallokeringar.Spårningar av spårningar är begränsade till
get_traceback_limit()
-ramar. Använd parametern nframe i funktionenstart()
för att lagra fler ramar.Modulen
tracemalloc
måste spåra minnesallokeringar för att ta en ögonblicksbild, se funktionenstart()
.Se även funktionen
get_object_traceback()
.
DomainFilter¶
- class tracemalloc.DomainFilter(inclusive: bool, domain: int)¶
Filtrera spår av minnesblock efter deras adressutrymme (domän).
Tillagd i version 3.6.
- inclusive¶
Om inclusive är
True
(include), matcha minnesblock som allokerats i adressrymdendomain
.Om inclusive är
False
(exkludera), matchas minnesblock som inte allokerats i adressutrymmetdomain
.
- domain¶
Adressrymd för ett minnesblock (
int
). Skrivskyddad egenskap.
Filtrera¶
- class tracemalloc.Filter(inclusive: bool, filename_pattern: str, lineno: int = None, all_frames: bool = False, domain: int = None)¶
Filtrera på spår av minnesblock.
Se funktionen
fnmatch.fnmatch()
för syntaxen för filename_pattern. Filändelsen'.pyc'
ersätts med'.py'
.Exempel:
Filter(True, subprocess.__file__)
innehåller bara spår av modulensubprocess
Filter(False, tracemalloc.__file__)
utesluter spår av modulentracemalloc
Filter(False, "<unknown>")
utesluter tomma spårningar
Ändrad i version 3.5: Filändelsen
'.pyo'
ersätts inte längre med'.py'
.Ändrad i version 3.6: Lagt till attributet
domain
.- domain¶
Adressrymd för ett minnesblock (
int
ellerNone
).tracemalloc använder domänen
0
för att spåra minnesallokeringar gjorda av Python. C-tillägg kan använda andra domäner för att spåra andra resurser.
- inclusive¶
Om inclusive är
True
(include), matchas endast minnesblock som allokerats i en fil med ett namn som matcharfilename_pattern
på radnummerlineno
.Om inclusive är
False
(exkludera), ignorera minnesblock som allokerats i en fil med ett namn som matcharfilename_pattern
på radnummerlineno
.
- lineno¶
Radnummer (
int
) för filtret. Om lineno ärNone
, matchar filtret vilket radnummer som helst.
- filename_pattern¶
Filnamnsmönster för filtret (
str
). Skrivskyddad egenskap.
- all_frames¶
Om all_frames är
True
kontrolleras alla ramar i tracebacken. Om all_frames ärFalse
kontrolleras endast den senaste ramen.Detta attribut har ingen effekt om traceback-gränsen är
1
. Se funktionenget_traceback_limit()
och attributetSnapshot.traceback_limit
.
Ram¶
Snapshot¶
- class tracemalloc.Snapshot¶
Ögonblicksbild av spår av minnesblock som allokerats av Python.
Funktionen
take_snapshot()
skapar en snapshot-instans.- compare_to(old_snapshot: Snapshot, key_type: str, cumulative: bool = False)¶
Beräkna skillnaderna med en gammal ögonblicksbild. Hämta statistik som en sorterad lista över
StatisticDiff
-instanser grupperade efter key_type.Se metoden
Snapshot.statistics()
för parametrarna key_type och cumulative.Resultatet sorteras från det största till det minsta efter: absolut värde av
StatisticDiff.size_diff
,StatisticDiff.size
, absolut värde avStatisticDiff.count_diff
,Statistic.count
och sedan efterStatisticDiff.traceback
.
- dump(filename)¶
Skriv in ögonblicksbilden i en fil.
Använd
load()
för att ladda om ögonblicksbilden.
- filter_traces(filters)¶
Skapa en ny
Snapshot
-instans med en filtreradtraces
-sekvens, filter är en lista överDomainFilter
- ochFilter
-instanser. Om filters är en tom lista, returneras en nySnapshot
-instans med en kopia av spåren.Alla inkluderande filter tillämpas på en gång, en spårning ignoreras om inga inkluderande filter matchar den. En spårning ignoreras om minst ett exklusivt filter matchar den.
Ändrad i version 3.6:
DomainFilter
-instanser accepteras nu även i filters.
- statistics(key_type: str, cumulative: bool = False)¶
Hämta statistik som en sorterad lista över
Statistic
-instanser grupperade efter key_type:key_type
beskrivning
'filename'
filename
'lineno'
filnam och radnummer
'traceback'
spårning
Om cumulative är
True
, kumuleras storlek och antal minnesblock för alla ramar i spårningen av en spårning, inte bara den senaste ramen. Det kumulativa läget kan endast användas med key_type lika med'filename'
och'lineno'
.Resultatet sorteras från det största till det minsta efter:
Statistic.size
,Statistic.count
och sedan efterStatistic.traceback
.
- traceback_limit¶
Maximalt antal bildrutor som lagras i spårningen av
traces
: resultatet avget_traceback_limit()
när ögonblicksbilden togs.
- traces¶
Spårningar av alla minnesblock som allokerats av Python: sekvens av
Trace
-instanser.Sekvensen har en odefinierad ordning. Använd metoden
Snapshot.statistics()
för att få en sorterad lista med statistik.
Statistik¶
- class tracemalloc.Statistic¶
Statistik över minnesallokeringar.
Snapshot.statistics()
returnerar en lista medStatistic
-instanser.Se även klassen
StatisticDiff
.- count¶
Antal minnesblock (
int
).
- size¶
Total storlek på minnesblock i byte (
int
).
StatisticDiff¶
- class tracemalloc.StatisticDiff¶
Statistisk skillnad på minnesallokeringar mellan en gammal och en ny
Snapshot
-instans.Snapshot.compare_to()
returnerar en lista medStatisticDiff
-instanser. Se även klassenStatistic
.- count¶
Antal minnesblock i den nya ögonblicksbilden (
int
):0
om minnesblocken har frigjorts i den nya ögonblicksbilden.
- count_diff¶
Skillnad i antal minnesblock mellan den gamla och den nya ögonblicksbilden (
int
):0
om minnesblocken har allokerats i den nya ögonblicksbilden.
- size¶
Total storlek på minnesblock i byte i den nya ögonblicksbilden (
int
):0
om minnesblocken har frigjorts i den nya ögonblicksbilden.
- size_diff¶
Skillnad i total storlek på minnesblock i byte mellan den gamla och den nya ögonblicksbilden (
int
):0
om minnesblocken har allokerats i den nya ögonblicksbilden.
Spåra¶
- class tracemalloc.Trace¶
Spårning av ett minnesblock.
Attributet
Snapshot.traces
är en sekvens av instanser avTrace
.Ändrad i version 3.6: Lagt till attributet
domain
.- domain¶
Adressrymd för ett minnesblock (
int
). Skrivskyddad egenskap.tracemalloc använder domänen
0
för att spåra minnesallokeringar gjorda av Python. C-tillägg kan använda andra domäner för att spåra andra resurser.
- size¶
Storleken på minnesblocket i byte (
int
).
Spårning¶
- class tracemalloc.Traceback¶
Sekvens av
Frame
-instanser sorterade från den äldsta ramen till den senaste ramen.En traceback innehåller minst
1
ram. Om modulentracemalloc
misslyckades med att hämta en ram används filnamnet"<unknown>"
på radnummer0
.När en ögonblicksbild tas begränsas spårningar av spårningar till
get_traceback_limit()
-ramar. Se funktionentake_snapshot()
. Det ursprungliga antalet bildrutor i traceback lagras i attributetTraceback.total_nframe
. Det gör det möjligt att veta om en traceback har avkortats av traceback-gränsen.Attributet
Trace.traceback
är en instans av instansenTraceback
.Ändrad i version 3.7: Ramarna sorteras nu från de äldsta till de senaste, i stället för från de senaste till de äldsta.
- total_nframe¶
Totalt antal bildrutor som utgjorde tracebacken före trunkering. Detta attribut kan sättas till
None
om informationen inte är tillgänglig.
Ändrad i version 3.9: Attributet
Traceback.total_nframe
lades till.- format(limit=None, most_recent_first=False)¶
Formatera traceback som en lista med rader. Använd modulen
linecache
för att hämta rader från källkoden. Om limit är inställt, formatera de limit senaste ramarna om limit är positiv. I annat fall formateras deabs(limit)
äldsta ramarna. Om most_recent_first ärTrue
, vänds ordningen på de formaterade ramarna och den senaste ramen returneras först istället för sist.Liknar funktionen
traceback.format_tb()
, förutom attformat()
inte inkluderar nya rader.Exempel:
print("Traceback (most recent call first):") for line in traceback: print(line)
Utdata:
Traceback (most recent call first): File "test.py", line 9 obj = Object() File "test.py", line 12 tb = tracemalloc.get_object_traceback(f())