Падіння пам'яті Python [закрито]


180

У мене є давно запущений сценарій, який, якщо дозволити працювати досить довго, буде споживати всю пам'ять у моїй системі.

Не вдаючись до деталей щодо сценарію, у мене є два питання:

  1. Чи слід дотримуватися "Кращих практик", які допоможуть запобігти появі витоків?
  2. Які існують методи налагодження витоків пам'яті в Python?

5
Я вважаю цей рецепт корисним.
Девід Шейн

Здається, надрукувати надто багато даних, щоб бути корисними
Casebash

1
@Casebash: Якщо ця функція друкує все, що ви серйозно робите не так. У ньому перелічені об'єкти з __del__методом, на який більше не посилаються, крім їх циклу. Цикл не може бути порушений через проблеми з __del__. Полагодьте це!
Гельмут Гроне

Відповіді:


106

Подивіться цю статтю: Відстеження витоку пам'яті пітона

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


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

Цей пакет пропонує ряд інших функцій. Перегляньте документацію пімплера , зокрема розділ Ідентифікація витоків пам'яті .


5
Варто зауважити, що це pymplerможе бути ПОЗНАЧЕНО . Якщо ви робите щось напівреальне, це може повністю пошкодити продуктивність вашої програми.
Підроблена назва

@sebpiq як не дивно, те ж саме відбувається і зі мною ... ти маєш уявлення, чому це відбувається? Швидкий погляд на вихідний код не дав реальних розумінь.
linusg

25

Дозвольте порекомендувати створений мною інструмент mem_top

Це допомогло мені вирішити подібне питання

Він просто миттєво показує головних підозрюваних у витоку пам'яті в програмі Python


1
це правда ... але це дає дуже мало способу використання / пояснення результатів
мені_

@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% часу, що є підказкою, але ледь допомагає у більшості випадків).

Я рекомендую використовувати трасемалок у поєднанні з піразитом . У 9 разів з 10, запускаючи топ-10 фрагментів в оболонку піразиту , ви отримаєте достатньо інформації та підказок, щоб виправити витік протягом 10 хвилин. Однак якщо ви все ще не можете знайти причину витоку, оболонка піразиту в поєднанні з іншими інструментами, згаданими в цій темі, ймовірно, дасть вам ще кілька підказок. Ви також повинні ознайомитися з усіма додатковими помічниками, які надає піразит (наприклад, програма перегляду пам’яті).



12

Вам слід спеціально ознайомитись із вашими глобальними чи статичними даними (тривалі дані про життя).

Коли ці дані зростають без обмежень, ви також можете отримати проблеми в Python.

Збирач сміття може збирати лише ті дані, на які вже не йдеться. Але ваші статичні дані можуть збирати елементи даних, які слід звільнити.

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

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


7

Для виявлення та пошуку витоків пам'яті для тривалих запущених процесів, наприклад, у виробничих середовищах, тепер ви можете використовувати stackimpact . Він використовує мікроелемент під ним. Більше інформації у цій публікації .

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


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 () і мати головну () ручку, коли потрібно викликати його ще раз. таким чином функція закінчується природним шляхом і очищається після себе.

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

7
Використання рекурсії таким чином також порушиться, якщо ви досягнете межі глибини рекурсії, оскільки Python не оптимізує хвостові дзвінки. За замовчуванням це 1000 рекурсивних дзвінків.
Лежати Райан

3

Не впевнений у "Кращих практиках" щодо витоку пам'яті в python, але python повинен очистити власну пам'ять, використовуючи сміттєзбірник. Тож головним чином я почав би з перевірки того, чи є круглі списки деяких коротких, оскільки їх смітник не забрав.


3
або посилання на предмети, які зберігаються назавжди тощо
matt b

3
Чи можете ви, хлопці, надати приклади круглих списків та об’єктів, які зберігаються назавжди?
Даніель

2

Це аж ніяк не вичерпні поради. Але перше, про що слід пам’ятати, пишучи з думкою уникнути майбутніх витоків пам’яті (циклів), - це переконатися, що все, що приймає посилання на зворотній дзвінок, повинно зберігати цей зворотний дзвінок як слабку орієнтир.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.