Spec-Zone.ru › Python 3.5

tracemalloc — Отслеживание выделения памяти

Новая версия 3.4.

Исходный код: Lib/tracemalloc.py

Модуль tracemalloc — это инструмент отладки для отслеживания блоков памяти, выделенных Python. Он предоставляет следующую информацию:

  • Трекбек, где был выделен объект
  • Статистику по выделенным блокам памяти по имени файла и номеру строки: общий размер, количество и средний размер выделенных блоков памяти
  • Вычисление различий между двумя снимками для обнаружения утечек памяти

Для отслеживания большинства блоков памяти, выделенных Python, модуль следует запустить как можно раньше, установив переменную среды PYTHONTRACEMALLOC на значение 1, или с помощью опции командной строки -X tracemalloc. Функцию tracemalloc.start() можно вызвать во время выполнения, чтобы начать отслеживание выделения памяти Python.

По умолчанию при отслеживании выделенного блока памяти сохраняется только самый последний кадр (1 кадр). Для сохранения 25 кадров при запуске: установите переменную среды PYTHONTRACEMALLOC на значение 25, или используйте опцию командной строки -X tracemalloc=25.

1. Примеры

1.1. Отображение 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() для получения дополнительных опций.

1.2. Вычисление различий

Сравнение двух снимков и отображение различий:

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().

1.3. Получение трекбека блока памяти

Код для отображения трекбека наибольшего блока памяти:

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. Трекбек может измениться, если загружается новый модуль.

1.4. Красивое отображение

Код для отображения 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]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, 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() для получения дополнительных опций.

2. API

2.1. Функции

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 в противном случае.

См. также функции start() и stop().

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().

2.2. Фильтр

class tracemalloc.Filter(inclusive: bool, filename_pattern: str, lineno: int=None, all_frames: bool=False)

Фильтр для отслеживания блоков памяти.

См. функцию fnmatch.fnmatch() для синтаксиса filename_pattern. Расширение файла '.pyc' заменяется на '.py'.

Примеры:

  • Filter(True, subprocess.__file__) включает только трассировки модуля subprocess
  • Filter(False, tracemalloc.__file__) исключает трассировки модуля tracemalloc
  • Filter(False, "<unknown>") исключает пустые стеки вызовов

Изменено в версии 3.5: Расширение файла '.pyo' больше не заменяется на '.py'.

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.

2.3. Кадр

class tracemalloc.Frame

Кадр стека вызовов.

Класс Traceback представляет собой последовательность экземпляров Frame.

filename

Имя файла (str).

lineno

Номер строки (int).

2.4. Снимок

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 — список экземпляров Filter. Если filters пустой, возвращается новый экземпляр Snapshot с копией трассировок.

Все включения фильтров применяются одновременно. Трассировка игнорируется, если не соответствует ни одному включению фильтра. Трассировка игнорируется, если хотя бы один исключающий фильтр соответствует ей.

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() для получения отсортированного списка статистики.

2.5. Статистика

class tracemalloc.Statistic

Статистика по выделению памяти.

Snapshot.statistics() возвращает список экземпляров Statistic.

См. также класс StatisticDiff.

count

Количество блоков памяти (int).

size

Общий размер блоков памяти в байтах (int).

traceback

Трек, где был выделен блок памяти, экземпляр Traceback.

2.6. 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.

2.7. Trace

class tracemalloc.Trace

Трек блока памяти.

Атрибут Snapshot.traces — последовательность экземпляров Trace.

size

Размер блока памяти в байтах (int).

traceback

Трек, где был выделен блок памяти, экземпляр Traceback.

2.8. Traceback

class tracemalloc.Traceback

Последовательность экземпляров Frame, отсортированных от самого последнего кадра к самому старому.

Трек содержит как минимум 1 кадр. Если модулю tracemalloc не удалось получить кадр, используется имя файла "<unknown>" на строке 0.

При создании снимка треки следов ограничены get_traceback_limit() кадрами. См. функцию take_snapshot().

Атрибут Trace.traceback — экземпляр Traceback.

format(limit=None)

Форматирует трек как список строк с переводами строк. Используйте модуль linecache для извлечения строк из исходного кода. Если limit задан, форматируются только limit последних кадров.

Аналогично функции 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.5/library/tracemalloc.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API