tracemalloc
— Отслеживание выделения памяти¶
Добавлено в версии 3.4.
Исходный код: Lib/tracemalloc.py
Модуль tracemalloc представляет собой средство отладки для отслеживания блоков памяти, выделенных Python. В нем содержится следующая информация:
- Трассировка, где объект был выделен
- Cтатистика по выделенным блокам памяти на имя файла и на номер строки: общий размер, количество и средний размер выделенных блоков памяти
- Вычислить различия между двумя снимками для обнаружения утечек памяти
Чтобы отследить большинство блоков памяти, выделенных Python, модуль
следует запустить как можно раньше, установив для переменной среды PYTHONTRACEMALLOC
значение 1
или используя параметр командной строки -X
tracemalloc
. Функцию tracemalloc.start()
можно вызвать во время выполнения, чтобы начать
трассировку Python выделения памяти.
По умолчанию трассировка выделенного блока памяти хранит только последние
фрейм (1 фрейм). Чтобы сохранить 25 фреймов при запуске, установите
для переменной среды PYTHONTRACEMALLOC
значение 25
или используйте параметр
командной строки -X
tracemalloc=25
.
Примеры¶
Показать топ-10¶
Отобразить 10 файлов, в которых выделяется наибольшее количество памяти:
import tracemalloc
tracemalloc.start()
# ... запустить ваше приложение ...
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()
# ... запустить ваше приложение ...
snapshot1 = tracemalloc.take_snapshot()
# ... вызвать функцию утечки памяти ...
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 KiB
Python исходного код для форматирования трейсбэки, и
все это происходит со времени предыдущего снимка файловой системы.
Если в системе недостаточно свободной памяти, снимки можно записать на диск с
помощью метода Snapshot.dump()
для анализа снимка в автономном режиме. Затем
используйте метод Snapshot.load()
для перезагрузки снимка.
Получить трейсбэк блока памяти¶
Код для отображения трейсбэк самого большого блока памяти:
import tracemalloc
# Хранить 25 фреймов
tracemalloc.start(25)
# ... запустить ваше приложение ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('traceback')
# выберите самый большой блок памяти
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()
# ... запустить ваше приложение ...
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()
.
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.
get_tracemalloc_memory
()¶ Получение информации об использовании памяти в байтах
tracemalloc
модуля используемый для хранения следов блоков памяти. Возвращаетint
.
-
tracemalloc.
is_tracing
()¶ True
, если модульtracemalloc
отслеживает Python выделения памяти,False
в противном случае.
-
tracemalloc.
start
(nframe: int=1)¶ Начать трассировку Python выделения памяти: установить хуки на Python распределители памяти. Собранные трейсбэки следов будут ограничены nframe кадрами. По умолчанию трассировка блока памяти хранит только самые последние фрейм: предел равен
1
. nframe должно быть больше или равно1
.Хранение более
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()
см. в функции filename_pattern. Расширение файла'.pyc'
заменяется на'.py'
.Examples:
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
(включают), сопоставляются только блоки памяти, выделенные в файле с именем, соответствующимfilename_pattern
в строке номерlineno
.Если inclusive является
False
(исключает), игнорируйте блоки памяти, выделенные в файле с именем, соответствующимfilename_pattern
в строке номерlineno
.
-
lineno
¶ Номер строки (
int
) фильтра. Если linenoNone
, фильтр соответствует любому номеру строки.
-
filename_pattern
¶ Шаблон имени файла фильтра (
str
). Собственность только для чтения.
-
all_frames
¶ Если all_frames
True
, проверяются все кадры трейсбэк. Если all_framesFalse
, проверяется только последняя фрейм.Этот атрибут не действует, если трейсбэк предел
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
сущность с копией трассировки.Фильтры all inclusive применяются одновременно, трассировка игнорируется, если ей не соответствуют фильтры inclusive. Трассировка игнорируется, если ей соответствует хотя бы один эксклюзивный фильтр.
Изменено в версии 3.6:
DomainFilter
сущности в настоящее время также принимаются в filters.
-
statistics
(key_type: str, cumulative: bool=False)¶ Получение статистики в виде отсортированного списка
Statistic
сущности, сгруппированных по key_type:key_type описание 'filename'
filename 'lineno'
filename и line number 'traceback'
traceback Если cumulative
True
, скопируйте размер и количество блоков памяти всех фреймов трейсбэк трассировки, а не только самых последних фрейм. Кумулятивный режим может быть используемый только с key_type, равными'filename'
и'lineno'
.Результат сортируется от наибольшего к наименьшему по:
Statistic.size
,Statistic.count
а затем поStatistic.traceback
.
-
traceback_limit
¶ Максимальное количество фреймов, сохраненных в трейсбэк
traces
: результатget_traceback_limit()
при создании снимка.
-
traces
¶ Следы всех блоков памяти, выделенных Python: последовательность
Trace
сущности.Последовательность имеет неопределенный порядок. Использовать метод
Snapshot.statistics()
для получения отсортированного списка статистики.
-
Статистическая величина¶
-
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()
.Trace.traceback
атрибут является сущностьTraceback
.Изменено в версии 3.7: Фреймы теперь сортируются от самых старых к самым последним, а не от самых последних к самым старым.
-
format
(limit=None, most_recent_first=False)¶ Отформатируйте трейсбэк как список строк с новыми строками. Использовать модуль
linecache
для извлечения строк из исходного код. Если limit установлен, отформатируйте limit самые последние кадры, если limit положительный. В противном случае отформатируйтеabs(limit)
самые старые кадры. Если most_recent_firstTrue
, порядок форматированных фреймов меняется на обратный, возвращая последний фрейм первым, а не последним.Аналогично функции
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())
-