tracemalloc
— Trace memory allocations¶
Нове в версії 3.4.
Вихідний код: Lib/tracemalloc.py
Модуль tracemalloc — це інструмент налагодження для відстеження блоків пам’яті, виділених Python. Він надає таку інформацію:
Зворотне відстеження місця розміщення об’єкта
Статистика виділених блоків пам’яті на ім’я файлу та номер рядка: загальний розмір, кількість і середній розмір виділених блоків пам’яті
Обчисліть різницю між двома знімками, щоб виявити витоки пам’яті
Для відстеження більшості блоків пам’яті, виділених Python, модуль слід запускати якомога раніше, встановивши змінну середовища PYTHONTRACEMALLOC
на 1
або використовуючи -X
tracemalloc
параметр командного рядка. Функцію tracemalloc.start()
можна викликати під час виконання, щоб розпочати відстеження розподілу пам’яті Python.
За замовчуванням трасування виділеного блоку пам’яті зберігає лише останній кадр (1 кадр). Щоб зберегти 25 кадрів під час запуску: установіть для змінної середовища PYTHONTRACEMALLOC
значення 25
або скористайтеся параметром командного рядка -X
tracemalloc=25
.
Приклади¶
Покажіть 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
Ми бачимо, що Python завантажив дані 4855 KiB
(байт-код і константи) з модулів і що модуль collections
виділив 244 KiB
для створення типів namedtuple
.
Перегляньте Snapshot.statistics()
для отримання додаткових параметрів.
Обчислити відмінності¶
Зробіть два знімки та покажіть відмінності:
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)
Приклад результату до/після виконання деяких тестів набору тестів Python:
[ 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
Ми бачимо, що Python завантажив 8173 KiB
даних модуля (байт-код і константи), і що це на 4428 KiB
більше, ніж було завантажено до тестів, коли було зроблено попередній знімок. Подібним чином модуль linecache
кешував 940 КіБ
вихідного коду Python для форматування відстеження, усе це з попереднього знімка.
Якщо в системі мало вільної пам’яті, знімки можна записати на диск за допомогою методу Snapshot.dump()
для аналізу знімка в автономному режимі. Потім скористайтеся методом Snapshot.load()
, перезавантажте знімок.
Отримати відстеження блоку пам’яті¶
Код для відображення зворотного відстеження найбільшого блоку пам’яті:
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)
Приклад результату набору тестів Python (зворотне відстеження обмежено 25 кадрами):
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)
Ми бачимо, що найбільше пам’яті було виділено в модулі importlib
для завантаження даних (байт-код і константи) з модулів: 870.1 KiB
. Трасування – це місце, де importlib
завантажував дані останнім часом: у рядку import pdb
модуля doctest
. Трасування може змінитися, якщо завантажується новий модуль.
Досить топ¶
Код для відображення 10 рядків, які виділяють найбільшу кількість пам’яті, з гарним виведенням, ігноруючи файли <frozen importlib._bootstrap>
і <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)
Приклад результату набору тестів 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
Перегляньте Snapshot.statistics()
для отримання додаткових параметрів.
Запис поточного та пікового розміру всіх відстежених блоків пам’яті¶
Наступний код неефективно обчислює дві суми, такі як 0 + 1 + 2 + ...
, створюючи список цих чисел. Цей список тимчасово займає багато пам’яті. Ми можемо використовувати get_traced_memory()
і reset_peak()
, щоб спостерігати за малим використанням пам’яті після обчислення суми, а також за максимальним використанням пам’яті під час обчислень:
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=}")
Вихід:
first_size=664, first_peak=3592984
second_size=804, second_peak=29704
Використання reset_peak()
гарантувало, що ми можемо точно записати пік під час обчислення small_sum
, навіть якщо він набагато менший, ніж загальний піковий розмір блоків пам’яті після виклику start()
. Без виклику reset_peak()
, second_peak
все одно буде піком з обчислення large_sum
(тобто рівним first_peak
). У цьому випадку обидва піки значно перевищують остаточне використання пам’яті, і це означає, що ми могли б оптимізувати (вилучивши непотрібний виклик list
і написавши sum(range(...))
).
API¶
Функції¶
- tracemalloc.get_object_traceback(obj)¶
Отримати зворотне відстеження, де було виділено об’єкт Python obj. Повертає екземпляр
Traceback
абоNone
, якщо модульtracemalloc
не відстежує виділення пам’яті або не відстежує виділення об’єкта.Дивіться також функції
gc.get_referrers()
іsys.getsizeof()
.
- tracemalloc.get_traceback_limit()¶
Отримайте максимальну кількість кадрів, що зберігаються в зворотній трасі.
Модуль
tracemalloc
має відстежувати виділення пам’яті, щоб отримати обмеження, інакше виникає виняткова ситуація.Обмеження встановлюється функцією
start()
.
- tracemalloc.get_traced_memory()¶
Отримайте поточний розмір і максимальний розмір блоків пам’яті, які відстежуються модулем
tracemalloc
, як кортеж:(current: int, peak: int)
.
- tracemalloc.reset_peak()¶
Установіть максимальний розмір блоків пам’яті, які відстежуються модулем
tracemalloc
, на поточний розмір.Нічого не робити, якщо модуль
tracemalloc
не відстежує виділення пам’яті.Ця функція лише змінює розмір записаного піку, але не змінює та не очищає жодні траси, на відміну від
clear_traces()
. Знімки, зроблені за допомогоюtake_snapshot()
перед викликомreset_peak()
, можна змістовно порівняти зі знімками, зробленими після виклику.Дивіться також
get_traced_memory()
.Нове в версії 3.9.
- tracemalloc.get_tracemalloc_memory()¶
Отримати дані про використання пам’яті в байтах модуля
tracemalloc
, який використовується для зберігання слідів блоків пам’яті. Повертаєint
.
- tracemalloc.is_tracing()¶
True
, якщо модульtracemalloc
відстежує виділення пам’яті Python,False
інакше.
- tracemalloc.start(nframe: int = 1)¶
Почніть відстежувати виділення пам’яті Python: установіть перехоплювачі на розподільниках пам’яті Python. Зібрані зворотні трасування трасувань будуть обмежені кадрами nframe. За замовчуванням трасування блоку пам’яті зберігає лише останній кадр: обмеження становить
1
. nframe має бути більше або дорівнювати1
.Ви все ще можете прочитати вихідну загальну кількість кадрів, які склали відстеження, переглянувши атрибут
Traceback.total_nframe
.Зберігання більш ніж 1 кадру корисне лише для обчислення статистики, згрупованої за
'traceback'
або для обчислення сукупної статистики: перегляньте методиSnapshot.compare_to()
іSnapshot.statistics()
.Зберігання більшої кількості кадрів збільшує навантаження на пам’ять і ЦП модуля
tracemalloc
. Використовуйте функціюget_tracemalloc_memory()
, щоб виміряти, скільки пам’яті використовується модулемtracemalloc
.Змінну середовища
PYTHONTRACEMALLOC
(PYTHONTRACEMALLOC=NFRAME
) і параметр командного рядка-X
tracemalloc=NFRAME
можна використовувати для запуску трасування під час запуску.Дивіться також функції
stop()
,is_tracing()
іget_traceback_limit()
.
- tracemalloc.stop()¶
Зупиніть відстеження розподілу пам’яті Python: видаліть перехоплювачі розподільників пам’яті Python. Також очищає всі раніше зібрані сліди блоків пам’яті, виділених Python.
Викличте функцію
take_snapshot()
, щоб зробити знімок слідів перед їх очищенням.Дивіться також функції
start()
,is_tracing()
іclear_traces()
.
- tracemalloc.take_snapshot()¶
Зробіть знімок слідів блоків пам’яті, виділених Python. Повернути новий екземпляр
Snapshot
.Знімок не включає блоки пам’яті, виділені до того, як модуль
tracemalloc
почав відстежувати виділення пам’яті.Відстеження трасування обмежено кадрами
get_traceback_limit()
. Щоб зберегти більше кадрів, використовуйте параметр nframe функціїstart()
.Модуль
tracemalloc
повинен відстежувати виділення пам’яті, щоб зробити знімок, дивіться функціюstart()
.Дивіться також функцію
get_object_traceback()
.
DomainFilter¶
- class tracemalloc.DomainFilter(inclusive: bool, domain: int)¶
Фільтрувати сліди блоків пам’яті за їх адресним простором (доменом).
Нове в версії 3.6.
- inclusive¶
Якщо inclusive має значення
True
(include), збігаються блоки пам’яті, виділені в адресному просторіdomain
.Якщо inclusive має значення
False
(виключити), збігаються блоки пам’яті, не виділені в адресному просторіdomain
.
- domain¶
Адресний простір блоку пам’яті (
int
). Властивість лише для читання.
фільтр¶
- class tracemalloc.Filter(inclusive: bool, filename_pattern: str, lineno: int = None, all_frames: bool = False, domain: int = None)¶
Фільтрувати сліди блоків пам’яті.
Перегляньте функцію
fnmatch.fnmatch()
, щоб дізнатися про синтаксис шаблон_назви_файлу. Розширення файлу'.pyc'
замінено на'.py'
.приклади:
Filter(True, subprocess.__file__)
містить лише сліди модуляsubprocess
Filter(False, tracemalloc.__file__)
виключає сліди модуляtracemalloc
Filter(False, "<unknown>")
виключає порожні відстеження
Змінено в версії 3.5: Розширення файлу
'.pyo'
більше не замінюється на'.py'
.Змінено в версії 3.6: Додано атрибут
domain
.- domain¶
Адресний простір блоку пам’яті (
int
абоNone
).tracemalloc використовує домен
0
для відстеження розподілу пам’яті, зробленого Python. Розширення C можуть використовувати інші домени для відстеження інших ресурсів.
- inclusive¶
Якщо inclusive має значення
True
(include), збігаються лише блоки пам’яті, виділені у файлі з іменем, яке відповідаєfilename_pattern
у номері рядкаlineno
.Якщо inclusive має значення
False
(виключити), ігнорувати блоки пам’яті, виділені у файлі з іменем, яке відповідаєfilename_pattern
у номері рядкаlineno
.
- lineno¶
Номер рядка (
int
) фільтра. Якщо lineno має значенняNone
, фільтр відповідає будь-якому номеру рядка.
- filename_pattern¶
Шаблон імені файлу фільтра (
str
). Властивість лише для читання.
- all_frames¶
Якщо all_frames має значення
True
, перевіряються всі кадри зворотного відстеження. Якщо all_frames має значенняFalse
, перевіряється лише останній кадр.Цей атрибут не діє, якщо обмеження зворотного відстеження дорівнює
1
. Перегляньте функціюget_traceback_limit()
і атрибутSnapshot.traceback_limit
.
рамка¶
знімок¶
- class tracemalloc.Snapshot¶
Знімок слідів блоків пам’яті, виділених Python.
Функція
take_snapshot()
створює екземпляр знімка.- compare_to(old_snapshot: Snapshot, key_type: str, cumulative: bool = False)¶
Обчисліть різницю за старим знімком. Отримати статистику як відсортований список екземплярів
StatisticDiff
, згрупованих за key_type.Перегляньте метод
Snapshot.statistics()
для параметрів key_type і cumulative.Результат сортується від найбільшого до найменшого за: абсолютним значенням
StatisticDiff.size_diff
,StatisticDiff.size
, абсолютним значеннямStatisticDiff.count_diff
,Statistic .count
, а потімStatisticDiff.traceback
.
- filter_traces(filters)¶
Створіть новий екземпляр
Snapshot
із відфільтрованою послідовністюtraces
, filters — це список екземплярівDomainFilter
іFilter
. Якщо filters є порожнім списком, поверніть новий екземплярSnapshot
із копією трасувань.Усі включені фільтри застосовуються одразу, трасування ігнорується, якщо жодні включені фільтри не відповідають йому. Трасування ігнорується, якщо йому відповідає хоча б один ексклюзивний фільтр.
Змінено в версії 3.6: Екземпляри
DomainFilter
тепер також приймаються в filters.
- statistics(key_type: str, cumulative: bool = False)¶
Отримати статистику як відсортований список екземплярів
Statistic
, згрупованих за key_type:key_type
опис
'ім'я файлу'
ім’я файлу
''лінено'
ім’я файлу та номер рядка
'відстеження''
простежити
Якщо cumulative має значення
True
, кумулювати розмір і кількість блоків пам’яті всіх кадрів зворотного відстеження трасування, а не лише останнього кадру. Кумулятивний режим можна використовувати лише з key_type, що дорівнює'filename'
і'lineno'
.Результат сортується від найбільшого до найменшого за:
Statistic.size
,Statistic.count
, а потім заStatistic.traceback
.
- traceback_limit¶
Максимальна кількість кадрів, що зберігаються у зворотній трасуванні
traces
: результатуget_traceback_limit()
під час створення знімка.
статистика¶
- class tracemalloc.Statistic¶
Статистика виділення пам’яті.
Snapshot.statistics()
повертає список екземплярівStatistic
.Дивіться також клас
StatisticDiff
.- count¶
Кількість блоків пам’яті (
int
).
- size¶
Загальний розмір блоків пам’яті в байтах (
int
).
StatisticDiff¶
- class tracemalloc.StatisticDiff¶
Різниця в статистиці виділення пам’яті між старим і новим екземплярами
Snapshot
.Snapshot.compare_to()
повертає список екземплярівStatisticDiff
. Дивіться також класStatistic
.- count¶
Кількість блоків пам’яті в новому знімку (
int
):0
, якщо блоки пам’яті було звільнено в новому знімку.
- count_diff¶
Різниця кількості блоків пам’яті між старим і новим знімками (
int
):0
, якщо блоки пам’яті були виділені в новому знімку.
- size¶
Загальний розмір блоків пам’яті в байтах у новому знімку (
int
):0
, якщо блоки пам’яті було звільнено в новому знімку.
- size_diff¶
Різниця загального розміру блоків пам’яті в байтах між старим і новим знімками (
int
):0
, якщо блоки пам’яті були виділені в новому знімку.
Слід¶
- class tracemalloc.Trace¶
Трасування блоку пам’яті.
Атрибут
Snapshot.traces
— це послідовність екземплярівTrace
.Змінено в версії 3.6: Додано атрибут
domain
.- domain¶
Адресний простір блоку пам’яті (
int
). Властивість лише для читання.tracemalloc використовує домен
0
для відстеження розподілу пам’яті, зробленого Python. Розширення C можуть використовувати інші домени для відстеження інших ресурсів.
- size¶
Розмір блоку пам’яті в байтах (
int
).
Простежити¶
- class tracemalloc.Traceback¶
Послідовність екземплярів
Frame
, відсортованих від найстарішого кадру до останнього.Трасування містить принаймні
1
кадр. Якщо модулюtracemalloc
не вдалося отримати кадр, використовується ім’я файлу"<unknown>"
під номером рядка0
.Коли робиться знімок, зворотне трасування трасування обмежується кадрами
get_traceback_limit()
. Перегляньте функціюtake_snapshot()
. Вихідна кількість кадрів зворотного відстеження зберігається в атрибутіTraceback.total_nframe
. Це дозволяє дізнатися, чи зворотне відстеження було скорочено обмеженням відстеження.Атрибут
Trace.traceback
є екземпляром екземпляраTraceback
.Змінено в версії 3.7: Кадри тепер сортуються від найстаріших до найновіших, а не від останніх до найстаріших.
- total_nframe¶
Загальна кількість кадрів, які складали зворотне трасування до скорочення. Для цього атрибута можна встановити значення
None
, якщо інформація недоступна.
Змінено в версії 3.9: Додано атрибут
Traceback.total_nframe
.- format(limit=None, most_recent_first=False)¶
Відформатуйте трасування як список рядків. Використовуйте модуль
linecache
, щоб отримати рядки з вихідного коду. Якщо встановлено ліміт, відформатуйте ліміт останніх кадрів, якщо ліміт додатний. В іншому випадку відформатуйте найстаріші кадриabs(limit)
. Якщо most_recent_first має значенняTrue
, порядок відформатованих кадрів змінюється на протилежний, повертаючи останній кадр першим, а не останнім.Подібно до функції
traceback.format_tb()
, за винятком того, щоformat()
не містить символів нового рядка.Приклад:
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())