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().
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
-
class tracemalloc.Frame -
Кадр стека следа.
Класс
Tracebackявляется последовательностью экземпляров классаFrame.-
filename -
Имя файла (
str).
-
lineno -
Номер строки (
int).
-
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: Теперь в 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–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.7/library/tracemalloc.html