Утечки памяти Python [закрыто]

180

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

Не вдаваясь в подробности о сценарии, у меня есть два вопроса:

  1. Есть ли какие-либо «передовые практики», которым нужно следовать, которые помогут предотвратить возникновение утечек?
  2. Какие методы существуют для устранения утечек памяти в Python?
Fragsworth
источник
5
Я нашел этот рецепт полезным.
Дэвид Шейн
Кажется, выдается слишком много данных, чтобы быть полезными
Casebash
1
@Casebash: Если эта функция печатает что-то, вы серьезно делаете это неправильно. В нем перечислены объекты с __del__методом, на которые больше не ссылаются, за исключением их цикла. Цикл не может быть разорван из-за проблем с __del__. Почини это!
Хельмут Гроне

Ответы:

106

Взгляните на эту статью: Отслеживание утечек памяти Python

Также обратите внимание, что модуль сбора мусора на самом деле может иметь установленные флаги отладки. Посмотрите на set_debugфункцию. Кроме того, посмотрите на этот код Gnibbler для определения типов объектов, которые были созданы после вызова.

ChristopheD
источник
83

Я опробовал большинство вариантов, упомянутых ранее, но нашел этот небольшой и интуитивно понятный пакет лучшим: pympler

Отследить объекты, которые не были собраны в мусор, довольно просто, посмотрите на этот небольшой пример:

установить пакет через pip install pympler

from pympler.tracker import SummaryTracker
tracker = SummaryTracker()

# ... some code you want to investigate ...

tracker.print_diff()

Вывод показывает вам все объекты, которые были добавлены, плюс память, которую они использовали.

Пример вывода:

                                 types |   # objects |   total size
====================================== | =========== | ============
                                  list |        1095 |    160.78 KB
                                   str |        1093 |     66.33 KB
                                   int |         120 |      2.81 KB
                                  dict |           3 |       840 B
      frame (codename: create_summary) |           1 |       560 B
          frame (codename: print_diff) |           1 |       480 B

Этот пакет предоставляет ряд дополнительных функций. Проверьте документацию pympler , в частности, раздел « Определение утечек памяти» .

Linqu
источник
5
Стоит отметить, что pymplerможет быть МЕДЛЕННО . Если вы делаете что-то наполовину в реальном времени, это может полностью снизить производительность вашего приложения.
Фальшивое имя
@sebpiq странно, то же самое происходит со мной ... у вас есть идеи, почему это происходит? Быстрый взгляд на исходный код не дал реального понимания.
linusg
26

Позвольте мне порекомендовать инструмент mem_top, который я создал

Это помогло мне решить аналогичную проблему

Это просто мгновенно показывает основные подозреваемые утечки памяти в программе Python

Денис Рыжков
источник
1
это правда ... но это дает очень мало способов объяснения использования / результатов
me_
@me_, этот инструмент документировал разделы «Использование» и «Объяснение результата». Должен ли я добавить объяснение типа «refs - это количество ссылок на объект, типы - это количество объектов этого типа, байты - это размер объекта» - не слишком ли это очевидно для документирования?
Денис Рыжков
Документы по использованию инструмента дают единственную строку с надписью «время от времени: logging.debug (mem_top ())», а его объяснение результатов - это реальный опыт автора по отслеживанию ошибок без контекста ... это не техническая спецификация, которая говорит разработчик именно то, на что они смотрят ... я не выбиваю твой ответ ... он показывает подозреваемых высокого уровня как выставленный счет ... он не дает адекватной документации для полного понимания результата использования ... например в выводе «Объясняя результаты» почему «GearmanJobRequest» явно проблема? нет объяснения почему ...
me_
1
Полагаю, я случайно выбил твой инструмент, ты - автор ... без обид я не хотел ...
me_
6
@me_, я только что добавил следующий шаг в «Использование», добавил раздел «Счетчики», добавил объяснение, почему именно Gearman был подозреваемым в этом реальном примере, задокументировал каждый необязательный параметр «mem_top ()» в коде, и загрузил все это как v0.1.7 - пожалуйста, посмотрите, может ли что-то еще быть улучшено. Спасибо! )
Денис Рыжков
18

Модуль Tracemalloc был интегрирован как встроенный модуль, начиная с Python 3.4, и, по-видимому, он также доступен для предыдущих версий Python в качестве сторонней библиотеки (хотя и не тестировал его).

Этот модуль способен выводить точные файлы и строки, которые занимали больше всего памяти. ИМХО, эта информация бесконечно более ценна, чем количество выделенных экземпляров для каждого типа (что в итоге приводит к большому количеству кортежей в 99% случаев, что является подсказкой, но в большинстве случаев едва помогает).

Я рекомендую вам использовать tracemalloc в сочетании с пиразитом . В 9 случаях из 10 запуск 10 лучших фрагментов в оболочке из пиразита даст вам достаточно информации и подсказок, чтобы исправить утечку в течение 10 минут. Тем не менее, если вы все еще не можете найти причину утечки, pyrasite-shell в сочетании с другими инструментами, упомянутыми в этой теме, вероятно, даст вам еще несколько советов. Вы также должны взглянуть на все дополнительные помощники, предоставляемые пиразитом (например, просмотрщик памяти).

user1527491
источник
pytracemalloc.readthedocs.io больше не существует
Dimitrios Mistriotis
12

Вы должны специально взглянуть на ваши глобальные или статические данные (долгоживущие данные).

Когда эти данные растут без ограничений, вы также можете получить проблемы в Python.

Сборщик мусора может собирать только те данные, на которые больше нет ссылок. Но ваши статические данные могут подключать элементы данных, которые должны быть освобождены.

Другой проблемой могут быть циклы памяти, но, по крайней мере, теоретически сборщик мусора должен находить и устранять циклы - по крайней мере, до тех пор, пока они не подключены к некоторым долгоживущим данным.

Какие виды долгоживущих данных особенно неприятны? Внимательно просматривайте любые списки и словари - они могут расти без ограничений. В словарях вы, возможно, даже не увидите появления проблемы, поскольку при доступе к диктовкам количество ключей в словаре может быть не слишком заметным для вас ...

Юргена
источник
7

Чтобы обнаруживать и обнаруживать утечки памяти для длительных процессов, например, в производственных средах, теперь вы можете использовать stackimpact . Он использует tracemalloc внизу. Больше информации в этом посте .

введите описание изображения здесь

Logix
источник
4

Что касается лучших практик, следите за рекурсивными функциями. В моем случае я столкнулся с проблемами с рекурсией (там, где не было необходимости). Упрощенный пример того, что я делал:

def my_function():
    # lots of memory intensive operations
    # like operating on images or huge dictionaries and lists
    .....
    my_flag = True
    if my_flag:  # restart the function if a certain flag is true
        my_function()

def main():
    my_function()

работа таким рекурсивным способом не вызовет сборку мусора и не очистит остатки функции, поэтому каждый раз при использовании памяти растет и растет.

Мое решение состояло в том, чтобы извлечь рекурсивный вызов из my_function () и иметь дескриптор main (), когда вызывать его снова. таким образом, функция завершается естественным образом и очищается после себя.

def my_function():
    # lots of memory intensive operations
    # like operating on images or huge dictionaries and lists
    .....
    my_flag = True
    .....
    return my_flag

def main():
    result = my_function()
    if result:
        my_function()
The4thIceman
источник
7
Использование рекурсии таким образом также нарушится, если вы достигнете предела глубины рекурсии, потому что Python не оптимизирует хвостовые вызовы. По умолчанию это 1000 рекурсивных вызовов.
Ложь Райану
3

Не уверен насчет «лучших практик» для утечек памяти в python, но python должен очистить свою собственную память сборщиком мусора. Поэтому в основном я бы начал с проверки кругового списка некоторых коротких, поскольку они не будут собраны сборщиком мусора.

martiert
источник
3
или ссылки на объекты, которые хранятся навсегда и т. д.
Matt B
3
Ребята, не могли бы вы привести примеры круговых списков и объектов, которые хранятся вечно?
Даниил
2

Это ни в коем случае не исчерпывающий совет. Но первое, о чем следует помнить, когда пишете с мыслью избежать будущих утечек памяти (циклов), это убедиться, что все, что принимает ссылку на обратный вызов, должно хранить этот обратный вызов как слабую ссылку.

Дмитрий Рубанович
источник