tracemalloc — Отслеживание выделения памяти
Новое в версии 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 KiB кода 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() для получения дополнительных параметров.
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) и опция командной строки-Xtracemalloc=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().
Фильтр областей
-
class tracemalloc.DomainFilter(inclusive: bool, domain: int) -
Фильтровать следы блоков памяти по их адресной области (домену).
Новое в версии 3.6.
-
inclusive -
Если inclusive
True(включить), соответствовать блокам памяти, выделенным в адресном пространстве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'.Примеры:
-
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.
-
Кадр
Снимок
-
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: В filters теперь также принимаются объекты
DomainFilter.
-
classmethod load(filename) -
Загрузка снимка из файла.
См. также
dump().
-
statistics(key_type: str, cumulative: bool=False) -
Получение статистики как отсортированного списка объектов
Statistic, сгруппированных по key_type:key_type
описание
'filename'имя файла
'lineno'имя файла и номер строки
'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).
-
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.
-
Трассировка
-
class tracemalloc.Trace -
Трассировка блока памяти.
Атрибут
Snapshot.traces— последовательность экземпляровTrace.Изменено в версии 3.6: Добавлен атрибут
domain.-
domain -
Адресное пространство блока памяти (
int). Только для чтения.tracemalloc использует домен
0для отслеживания выделения памяти, выполненного Python. Расширения C могут использовать другие домены для отслеживания других ресурсов.
-
size -
Размер блока памяти в байтах (
int).
-
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())
-
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/library/tracemalloc.html