html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Управление памятью в Питоне

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

На первый взгляд все просто: программист создает объект, а когда этот объект становится не нужен - он автоматически удаляется. Обычно так все и происходит, но иногда система дает сбой - память постоянно растет, встроенный garbage collector не работает.
Программист впадает в легкую панику и начинает ругать сквозь зубы "чертов язык программирования" и самого Гвидо ван Россума, попутно стараясь разобраться в проблеме. Чаще всего это заканчивается откатом исходников до версии "все вроде бы хорошо" - без понимания настоящей причины.

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

Я попытаюсь показать, как работает этот механизм управления памятью в Питоне, и, главное, как он не работает. Чудеса - только в сказках.

Итак, с созданием объекта проблем никогда не бывает - только с его удалением. К слову, в Питоне все - объекты. Классы, переменные, функции, модули, число 3.14 и строка 'я - Андрей'. Исключений нет.

Проблемы бывают с удалением. Вернее, само по себе освобождение памяти тоже работает отлично. Беда в другом. Программист ожидает, что объект будет удален - ведь он больше этому программисту не нужен. А Питон думает иначе. В результате - конфликт интересов, Питон априори выигрывает. Программист получает головную боль.

Чтобы понять, почему эта ситуация иногда происходит, нужно углубиться в детали.

Исторически сложилось так, что в Питоне существуют два механизма для освобождения памяти - decref и garbage collector. Считаю это большим достоинством, и чуть позже объясню почему.

Начнем с первого. Питон считает ссылки на объект. Это количество переменных, ссылающихся на него.

>>> import sys
>>> a = 'Hello world'
>>> b = a
>>> sys.getrefcount(a)
3
>>> sys.getrefcount(b)
3
>>> del a
>>> sys.getrefcount(b)
2

Всегда отнимаем единицу от getrefcount - она автоматически добавляется при вызове функции.

Пока что все просто. Когда удаляется ссылка - счетчик уменьшается на единицу. Когда он становится равнным нулю - удаляется сам объект. Это - decref (по названию макроса в C API, делающего всю работу).

Теперь - более сложный пример. Дерево.

>>> class Parent(object):
...     def __init__(self):
...         self.children = []
...     def add(self, ch):
...         self.children.append(ch)
...         ch.parent = self
...
>>> class Child(object):
...     def __init__(self):
...         self.parent = None
...
>>>
>>> p = Parent()
>>> p.add(Child())
>>> p

>>> p.children
[]
>>> sys.getrefcount(p)
3
>>> sys.getrefcount(p.children[0])
3

Parent имеет ссылку на child, а тот в свою очередь - на родителя. Даже если мы удалим все внешние ссылки - они друг на друга все еще ссылаются, счетчик ссылок у каждого по единице (если добавили несколько child - у parent, соответствено, больше). Объекты остались в памяти, хотя программисту они уже не нужны - он "выбросил их и забыл". Проблема, думаю, ясна. Мусор.

Тогда появился второй способ - garbage collector (кажется, начиная с версии 2.1. Точно не помню, но помню, как ему радовался). Управление им - через модуль gc.
Коротко работу собирателя мусора можно описать так:
- есть три поколения объектов
- когда новый объект создается - сразу же попадает в первое поколение
- считается количество созданных/удаленных объектов
- если разница больше порога - запускается умный cycle finder
- если объект все еще не удален даже gc - он перемещается в более старое поколение
- если дело совсем худо - поймаем нашего нарушителя в gc.garbage
- все настраивается - смотрите документацию по gc.
- gc предоставляет еще много интересной информации, как-то: кто ссылается на объект и на кого он ссылается, кто попадает в garbage, список всех объектов, живущих в Питоне и т.д.
- детали на самом деле не очень важны.

Cycle finder пытается найти cycle dependencies - циклические зависимости (я буду называть их кольцами) - и удалить их. Т.е. если ты ссылаешься на меня, а я на тебя - и никто на нас снаружи - мы попадем под garbage collector и нас успешно разименуют.
Рано или поздно. Пиковое потребление памяти может быть довольно большим, но "в среднем по больнице температура 36.6". В тяжелых случаях можно принудительно запустить gc.collect() - но это выглядит как-то не кошерно.

Обычно все работает и позволяет ничего не делать в случае parent-child. Проблемы возникают, когда один из объектов кольца имеет метод __del__ или написан как extension, т.е. не на Питоне. Второй случай замнем для ясности - хотя для меня он весьма актуален.

Вернемся к __del__. Очень полезный метод, позволяющий сделать "уборку за собой". Например, закрыть файл логов, отсоединиться от базы данных и т.д. Проблема в том, что garbage collector вычислил кольцо, в котором, возможно, есть несколько объектов с __del__. И __del__ от parent может использовать свой child, который уже удален - получим странную ошибку. В такие интимные детали garbage collector не вникает, просто помещает все кольцо в мусорник - gc.garbage.
При этом оставляя программисту возможность посмотреть на это безобразие и разрулить ситуацию самому. Никогда такого не делал и считаю дурным тоном - мало ли кто в мусорник попадет, а мне за всех отвечать...

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

Достоинства двойного способа удаления объектов:
- если вы аккуратны и внимательны - получите минимальное использование памяти и явные вызовы __del__ aka destructor.
- иначе обычно объект все же удалится, пусть не сразу и с некторыми ограничениями. Таких примеров - большинсво.

Если будет интересно - о слабых ссылках в следующей статье.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с asvetlov.blogspot.ru

11

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • wrise007
          • домен blogspot.ru
          • домен asvetlov.blogspot.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции