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

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

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

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

9 ответов


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

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


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


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

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


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

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

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

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

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


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

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

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


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


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

enter image description here


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


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

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