2009-09-16 2 views
112

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

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

  1. Существуют ли какие-либо «Best Practices», чтобы следовать, которые помогут предотвратить утечку возникновения?
  2. Какие существуют методы для отладки утечек памяти в Python?
+3

Я нашел [этот рецепт] (http://code.activestate.com/recipes/65333/) полезным. –

+0

Кажется, распечатывают слишком много данных, чтобы быть полезными – Casebash

+1

@Casebash: Если эта функция печатает все, что вы серьезно делаете неправильно. Он перечисляет объекты с методом '__del__', которые больше не ссылаются, кроме их цикла. Цикл не может быть прерван из-за проблем с '__del__'. Почини это! –

ответ

67

Посмотрите на эту статью: Tracing python memory leaks

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

4

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

+3

или ссылки на объекты, которые хранятся вечно и т. д. –

+0

Можете ли вы, ребята, представить примеры круговых списков и объектов, которые хранятся навсегда? – Daniel

8

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

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

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

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

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

3

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

13

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

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

+0

Это правда ... но это дает очень мало для объяснения использования/результатов –

+0

@me_, этот инструмент имеет как разделы «Использование», так и «Объяснительный результат». Должен ли я добавить объяснение вроде «refs - количество ссылок от объекта, типы - количество объектов этого типа, байты - размер объекта» - не было бы слишком очевидным документировать это? –

+0

В документах по использованию инструмента дается одна строка: «время от времени: logging.debug (mem_top())», в то время как объяснение результатов - это реальный опыт отслеживания ошибок автора без контекста ... это не техническая спецификация, которая говорит dev точно, на что они смотрят ... Я не сбиваю ваш ответ ... он показывает подозреваемых на высоком уровне, как выставленный счет ... он не дает адекватной документации, чтобы полностью понять результат использования ... для Например, в разделе «Объяснение результатов» почему «GearmanJobRequest», очевидно, проблема? никакое объяснение почему ... –

51

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

+1

Смешная вещь ... моя утечка памяти фактически исчезла, когда я начал использовать пемплер, чтобы попробовать его отслеживать. Вероятно, проблема с сборкой мусора ... – sebpiq

+1

Стоит отметить, что 'pympler' может быть ** SLOW **. Если вы делаете что-то полуреалистичное, это может полностью испортить производительность вашего приложения. –

2

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

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

Использование рекурсии таким образом также будет нарушено, если вы нажмете ограничение глубины рекурсии, потому что Python не оптимизирует хвостовые вызовы. По умолчанию это 1000 рекурсивных вызовов. –

3

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

enter image description here

4

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

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

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

Смежные вопросы