tracemalloc
— Трассировка выделения памяти
Добавлено в версии 3.4.
Модуль tracemalloc — это инструмент отладки для трассировки блоков памяти, выделенных Python. Он предоставляет следующую информацию:
- Трассировка, где был выделен (allocated) объект
- Статистика по выделенным блокам памяти по имени файла и по номеру строки: общий размер, количество и средний размер выделенных блоков памяти
- Вычислите различия между двумя снимками для обнаружения утечек памяти
Чтобы отследить большинство блоков памяти, выделенных Python, модуль следует
запустить как можно раньше, установив для переменной среды
PYTHONTRACEMALLOC
значение 1
или используя параметр командной
строки -X
tracemalloc
. Функцию tracemalloc.start()
можно
вызвать во время выполнения, чтобы начать отслеживание выделения памяти
Python.
По умолчанию трассировка выделенного блока памяти сохраняет только самый
последний фрейм (1 фрейм). Чтобы сохранить 25 фреймов при запуске:
устанавливает для переменной среды PYTHONTRACEMALLOC
значение 25
или используйте параметр командной строки -X
tracemalloc=25
.
Примеры
Показать верхнюю десятку
Показать 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.
clear_traces
() Очистить следы блоков памяти, выделенных Python.
См. также
stop()
.
-
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
(включить), сопоставляет блоки памяти, выделенные в адресном пространствеdomain
.Если inclusive равен
False
(исключить), сопоставить блоки памяти, не выделенные в адресном пространствеdomain
.
-
domain
Адресное пространство блока памяти (
int
). Свойство только для чтения.
-
Filter
-
class
tracemalloc.
Filter
(inclusive: bool, filename_pattern: str, lineno: int=None, all_frames: bool=False, domain: int=None) Фильтр по следам блоков памяти.
См. функцию
fnmatch.fnmatch()
для синтаксиса filename_pattern. Расширение файла'.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
(включить), сопоставляются только блоки памяти, выделенные в файле с именем, совпадающим с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
.
Frame
Snapshot
-
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
.
-
dump
(filename) Записать снимок в файл.
Используйте
load()
, чтобы перезагрузить снимок.
-
filter_traces
(filters) Создать новый экземпляр
Snapshot
с отфильтрованной последовательностьюtraces
, filters — это список экземпляровDomainFilter
иFilter
. Если filters — пустой список, возвращает новый экземплярSnapshot
с копией трассировок.Все включающие фильтры применяются сразу, трасса игнорируется, если ни один из включающих фильтров не соответствует ей. Трассировка игнорируется, если ей соответствует хотя бы один эксклюзивный фильтр.
Изменено в версии 3.6: Экземпляры
DomainFilter
теперь также принимаются в filters.
-
classmethod
load
(filename) Загрузить снимок из файла.
См. также
dump()
.
-
statistics
(key_type: str, cumulative: bool=False) Получить статистику в виде отсортированного списка экземпляров
Statistic
, сгруппированных по key_type:key_type описание 'filename'
имя файла 'lineno'
имя файла и номер строки '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()
, чтобы получить отсортированный список статистики.
-
Statistic
-
class
tracemalloc.
Statistic
Статистика по выделению памяти.
Snapshot.statistics()
возвращает список экземпляровStatistic
.См. также класс
StatisticDiff
.-
count
Количество блоков памяти (
int
).
-
size
Общий размер блоков памяти в байтах (
int
).
-
traceback
Трассировка, где был выделен блок памяти, экземпляр
Traceback
.
-
StatisticDiff
-
class
tracemalloc.
StatisticDiff
Статистическая разница в выделении памяти между старым и новым экземпляром
Snapshot
.Snapshot.compare_to()
возвращает список экземпляровStatisticDiff
. См. также классStatistic
.-
count
Количество блоков памяти в новом снимке (
int
):0
, если блоки памяти были освобождены в новом снимке.
-
count_diff
Разница в количестве блоков памяти между старым и новым снимками (
int
):0
, если блоки памяти были выделены в новом снимке.
-
size
Общий размер блоков памяти в байтах в новом снимке (
int
):0
, если блоки памяти были освобождены в новом снимке.
-
size_diff
Разница общего размера блоков памяти в байтах между старым и новым снимками (
int
):0
, если блоки памяти были выделены в новом снимке.
-
traceback
Трассировка, где были выделены блоки памяти, экземпляр
Traceback
.
-
Trace
-
class
tracemalloc.
Trace
След блока памяти.
Атрибут
Snapshot.traces
представляет собой последовательность экземпляровTrace
.Изменено в версии 3.6: Добавлен атрибут
domain
.-
domain
Адресное пространство блока памяти (
int
). Свойство только для чтения.tracemalloc использует домен
0
для отслеживания выделения памяти, сделанного Python. Расширения C могут использовать другие домены для отслеживания других ресурсов.
-
size
Размер блока памяти в байтах (
int
).
-
traceback
Трассировка, где был выделен блок памяти, экземпляр
Traceback
.
-
Traceback
-
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_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())
-