Утечка памяти Python

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

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

  • Есть ли какие-либо "лучшие практики", которые помогут предотвратить утечку?
  • Какие существуют методы для отладки утечек памяти в Python?

Ответ 1

Посмотрите на эту статью: Отслеживание утечек памяти python

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

Ответ 2

Я опробовал большинство опций, упомянутых ранее, но нашел этот маленький и интуитивно понятный пакет лучшим: 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

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

Ответ 3

Позвольте мне рекомендовать mem_top инструмент,
что помогло мне решить подобную проблему.

Он просто мгновенно отображает главных подозреваемых в утечке памяти в программе Python.

Ответ 4

Вы должны специально посмотреть на свои глобальные или статические данные (длинные живые данные).

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

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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