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().
Запись текущего и пикового размера всех отслеживаемых блоков памяти
Следующий код неэффективно вычисляет две суммы, подобные 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.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.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) и параметр командной строки-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) -
Фильтр трассировок блоков памяти.
Синтаксис filename_pattern см. в описании функции
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(включение), отбирать только блоки памяти, выделенные в файле с именем, соответствующим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.Описание параметров key_type и cumulative см. в методе
Snapshot.statistics().Результат сортируется по убыванию следующих значений: абсолютное значение
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(), чтобы получить отсортированный список статистики.
-
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(). Исходное количество кадров трассировки стека сохраняется в атрибутеTraceback.total_nframe. Это позволяет определить, была ли трассировка стека усечена из-за установленного предела.Атрибут
Trace.tracebackявляется экземпляромTraceback.Изменено в версии 3.7: Теперь кадры отсортированы от самого старого к самому последнему, а не от самого последнего к самому старому.
-
total_nframe -
Общее количество кадров, составлявших трассировку стека до усечения. Если информация недоступна, этому атрибуту можно присвоить значение
None.
Изменено в версии 3.9: Добавлен атрибут
Traceback.total_nframe.-
format(limit=None, most_recent_first=False) -
Форматировать трассировку стека как список строк. Для получения строк исходного кода используется модуль
linecache. Если задано значение 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–2025 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/tracemalloc.html