Удаление объектов сборщиком мусора

На Хабре появилась толковая статьяо неприятностях, которые может доставить Garbage Collector.

Отмечу актуальность описания проблемы и полную корректность решения для tornado.

Однако не могу не обратить внимание на слабое освещение того, как именно работает сборщик мусора в CPython.

Почему при работающем garbage collector появляется так много неудаляемых объектов?

Немного теории.

Сборщик мусора имеет три поколения (счёт начинается с нуля). При создании объекта он попадает в нулевое поколение.

У каждого поколения есть счётчик и порог. Работает эта пара так:

  • При добавлении объекта в поколение счётчик увеличивается.
  • При выбывании из поколения счётчик уменьшается.
  • Когда счётчик превысит пороговое значение — по всем объектам из поколения пройдётся сборщик мусора. Кого найдёт — удалит.
  • Все выжившие в поколении объекты перемещаются в следующее (из нулевого в первое, из первого во второе). Из второго поколения объекты никуда не попадают и остаются там навечно.
  • Перемещённые в следующее поколение объекты меняют соответствующий счетчик, и операция может повториться уже для следующего поколения.
  • Счётчик текущего поколения сбрасывается.

Объекты, подлежащие уничтожению но имеющие переопределённый метод __del__ не могут быть собраны. Причина проста: эти объекты могут ссылаться друг на друга.

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

  • Деструктор объекта a для работы требует объект b.
  • Последний в своём деструкторе обращается к объекту a.
  • Если вызовем __del__ у a, то деструктор b не сможет отработать нормально. Ссылка на a будет иметь значение None.

Чтобы не заставлять программиста корректно разрешать такие ситуации было принято решение не уничтожать подобные объекты а просто перемещать их в gc.garbage — и дальше программист пусть сам разбирается что делать с этим мусором.

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

Перейдём к практической части.

Пример

Для иллюстрации рассмотрим немного изменённый пример из приведенной в самом начале статьи.

Имеем классическую древовидную структуру:

class Node(object):
parent = None

def __init__(self, *children):
self.children = list(children)
for node in self.children:
node.parent = self

@classmethod
def tree(cls, depth=1, numchildren=1):
if depth == 0:
return []
return [cls(*cls.tree(depth-1, numchildren))
for _ in range(numchildren)]

Родитель и потомки напрямую связаны друг с другом циклической связью. Метод tree создает дерево нужной глубины.

Добавляем garbage collection hook для того чтобы увидеть когда срабатывает сборщик мусора и сколько объектов он уничтожает:

import gc

def gc_cb(phase, info):
if not info['collected'] and not info['uncollectable']:
return
print("{0}:t{1[generation]}t{1[collected]}t{1[uncollectable]}".format(
phase, info))

gc.callbacks.append(gc_cb)

Наконец, делаем много-много наших деревьев и смотрим как они разрушаются:

for n in range(20):
for _ in range(n):
Node.tree(depth=5, numchildren=6)

Пороги стоят стандартные:

>>> gc.get_threshold()
(700, 10, 10)

700 объектов в нулевом поколении и по 10 в первом и во втором.

Анализ

Теперь о том, почему образуется столько мусора.

Пример напечатает что-то вроде такого (вырезка из очень длинного результата):

...
stop: 1, 4665, 0
stop: 2, 79305, 0
stop: 1, 4665, 0
stop: 2, 79305, 0
stop: 1, 4665, 0
stop: 1, 4665, 0
stop: 1, 4665, 0
stop: 2, 97965, 0
stop: 1, 4665, 0
stop: 2, 79305, 0
stop: 1, 4665, 0
...

За один вызов Node.tree(depth=5, numchildren=6) создается 9330 тесно связанных объектов, которые нельзя разрушить в 0 поколении (помним, что порог 700). Значит они попадают в первое, а большая часть даже во второе поколение (9330>700*10). Наконец все 9330 объекта созданы, можно разрушать.

На уменьшении счётчиков ссылок на объекты ничего убрать не получится. Поэтому ждём, когда опять превысим порог в 700 (на следующем вызове Node.tree, конечно).

Собираем нулевое поколение (оно оказывается заполнено свежими данными и поживиться почти ничем не удаётся).

А сборщик мусора для поколения 1 вызовется только если туда попадут как минимум 10 объектов из поколения 0.

Хорошо, мы добрались до сбора в 1 поколении. Часть циклов мож
но уничтожить сразу (два поколения для анализа лучше одного), некоторые переправляются в поколение 2. В котором сборщик запускается тоже если в свою очередь превысили порог.

Что случается ещё реже и таким образом наши объекты накапливаются во втором поколении. Когда сборщик мусора доходит до него, то всё чистит.

Проблема в том, что до последнего поколения дело доходит относительно редко.

В результате имеем не слишком типичный для сборщика мусора случай.

Чиним

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

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

Воспользуемся слабыми ссылками на родителя:

import weakref

class Node(object):
parent = None

def __init__(self, *children):
self.children = list(children)
for node in self.children:
node.parent = weakref.proxy(self)

Я предпочитаю weakref.ref как дающий больший контроль (всегда можно добавить свойство):

class Node(object):
_parent = None

def __init__(self, *children):
self.children = list(children)
for node in self.children:
node._parent = weakref.ref(self)

@property
def parent(self):
if self._parent is None:
return None
else:
return self._parent()

В любом варианте дело до сборщика мусора не дойдёт и объекты будут уничтожены сразу как только перестанут быть нужны.

Если вариант со слабыми ссылками почему-то не проходит можно просто увеличить пороги. У нас создаётся за раз 9330 объектов? Поставим порог для первого поколения в 10000.

gc.set_threshold(10000, 100, 100)

Результат выглядит куда лучше:

...
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 1, 919005, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
...

Как видим сборщик мусора уничтожает почти всё на первом проходе, и лишь иногда требуется второй. Правда, смущает цифра 919005.

Именно потому что не всё прибивается на первом проходе, а второй наступает нескоро.

Уменьшаем второй порог:

gc.set_threshold(10000, 10, 10)

Ага, теперь всё красиво:

...
stop: 1, 83970, 0
stop: 0, 9330, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 1, 74640, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
stop: 1, 102630, 0
stop: 0, 4665, 0
stop: 0, 4665, 0
...

Выводы

В результате всё просто. Используем слабые ссылки. Если это по каким-то причинам невозможно — поднимаем пороги.

Но при этом нужно помнить, что сборщик мусора будет запускаться реже.

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

Автор: Andrew Svetlov

Украшение детской игрушками хэндмэйд

Чем украшают и дополняют интерьер детской комнаты? Конечно же, игрушками! Здорово, когда игрушки сшиты  или сделаны своими руками. Особенно, если ваше чадо станет непосредственным участником процесса создания игрушки. И не нужно ждать лучших времен! Берите в руки ткань и швейные принадлежности и беритесь за дело. Как украсить детскую игрушками хэндмэйд – тема сегодняшней статьи.

Украшение детской игрушками

Украшение детской игрушками

Читать

Пескоцемент в строительстве: применение и оптимальный расход

пескоцемент

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

Читать

RetroShare. Обмен файлами

Продолжаем серию статей про RetroShare. Сегодня научимся расшаривать папки и файлы и качать чужие. Естественно, если Ваши друзья дали общий доступ к своим данным.
Вкладка «File Sharing» содержит в себе пять вкладок. Каждая из них отвечает за какую-либо операцию. Рассмотрим каждую из них по-отдельности.


Первая вкладка «Downloads«, на которой мы сможем наблюдать процесс скачивания файлов, а также выполнять определенные действия над скачанными и скачивающимися файлами.
Описывать колонки вкладки смысла нет. Все и так понятно. Части файлов и скачанные файлы хранятся в папках, которые Вы указывали в настройках программы.
Нажав правую кнопку мыши на любом из скачиваемых файлов — мы увидим контекстное меню, позволяющее управлять файлами и некоторыми функциями загрузки.
С закачанным файлом, а также файлом, находящимся в процессе закачки, можно делать следующие операции:
1. Воспроизвести — без комментариев)))
2. Priority (Speed)… — выставляем необходимую скорость закачки: Slower (низкая), Awerage (обычная), Faster (высокая).
3. Chunk strategy — выставляем размер качающихся блоков: Streaming (потоковая передача), Progressive (прогрессивный) и Random (случайный).
4. Rename file… — переименовать файл.
5. Set destination directory — выбираем папку по умолчанию.
6. Open file — открыть файл (если текстовый, либо еще какой).
7. Preview File — предпросмотр файла.
8. Open Folder — открыть папку, куда скачался файл.
9. Details — детали файла. При нажатии открывается следующее окно:

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

 
10. Clear Completed — очистить выполненные. Убираем записи о выполненных закачках с экрана.
11. Скопировать (вставить) ссылку RetroShare — следующие два пункта меню. Копируем либо вставляем ссылку.
12. Show cache transfers — ставим галочку для показа передачи кеша файла.
13. Download from collection file… — загрузка файла коллекции.
Вкладка «Uploads«, в которой отображаются файлы и прогресс-бар их выгрузки .
У меня пустой экран, ибо никто не качает))
 
 
Вкладка «Поиск«. В ней мы имеем возможность произвести поиск файлов по ключевым словам.
Сложного тут ничего нет. Соответственно расписывать не буду. Разберетесь сами.
 
Вкладка «Friends files» (файлы друзей). В этой вкладке отображаются расшаренные папки и файлы Ваших друзей, которые можно просматривать и скачивать себе. Эта вкладка — то, ради чего создавалась эта программа.
При нажатии правой кнопки мыши на файле либо папке мы видим контекстное меню как на картинке выше. При выборе пункта меню «Скачать» — выбранный файл переносится во вкладку «Downloads», где можно отслеживать процесс закачки.
 
Вкладка «My files» (мои файлы). Тут мы сможем добавить свои папки и файлы для общего использования. А также видим те данные, которые мы выложили.
Теперь будем добавлять свои файлы для своих друзей. Для этого нажимаем на пиктограмму желтой папки с зеленым крестиком. Видим вот такое вот окно:
 
В этом окне Вы увидите все папки, которые были расшарены и права доступа к ним. Эти папки можно редактировать и удалять. Мы же будем добавлять. Для этого нажимаем кнопку «Добавить«. Появится следующее окно:
 
Указываем «Local path» (локальный путь). Это местонахождение папки, которую Вы ходите добавить, на Вашем винте. Либо прописываем ручками путь до папки (если знаем наизусть), либо нажимаем кнопку «Выбор файла» и выбираем в стандартном окне необходимую папку. 
Затем в «Virtual Folder» (виртуальная папка) указываем название расшариваемой папки. Оно может быть любым.
Теперь выставим права доступа к этой папке. Это делается в блоке «Share Flags and groups«. Это три картинки. При выборе первой Ваши друзья, добавленные в какую-либо группу, будут иметь анонимный тоннель до данной директории. Видима для всех друзей в группе друзей. При выборе второй — папка будет не видна для всех остальных друзей, не входящих списки групп друзей. Третья картинка — папка видима и доступна для всех друзей, не вошедших в какую-либо группу.
Теперь о группах друзей. В правом углу окна отмечаем крестиком группы друзей, которым будет доступна и видна папка. Это группы: Друзья, Family (Семья), Co-workers (сослуживцы), Other Contacts (прочие контакты), Favorites (фавориты).
 
Теперь некоторые нюансы расшаривания. При расшаривании какой-либо папки программа сканирует каждый файл этой папки. Это может занять определенное время. Так что сразу же Ваши друзья не увидят этих папок. Процесс сканирования добавляется в нижней части программы, в котором видны следующие параметры: 
 
— количество кешированных файлов (3 из 9), 
— общий размер файла и процент кеширования, 
— название файла. 
 
Наблюдается некоторое зависание при множестве мелких файлов в папке. Имеется ввиду хеширование. До 25000 файлов кеширование еще проходит, а выше — зависает, только не определил на какой период. Терпежа не хватило. Еще одна фишка — разделы размером 500 ГБ, но с видеофайлами пережевывает нормально, а кучу мелких из раздела, размером до 100 ГБ ни в какую не хочет нормально вставлять. Так что учтите это при добавлении папок.
 
 
В этой статье мы разобрали действия по добавлению и скачиванию файлов друг у друга. В следующей статье будем разбираться со встроенными чатами.

Автор: Роман Дмитриевич

Максимальные проценты по вкладам от Джей энд Ти Банка — только до конца сентября!

Максимальные проценты по вкладам от Джей энд Ти Банка — только до конца сентября!

Максимальные проценты по вкладам от Джей
энд Ти Банка — только до конца сентября!
================================================================================
Александр Сторожук on 06/09/2013 20:19:00

Джей энд Ти Банк на сегодняшний день
предлагает одни из самых выгодных на рынке
условий для размещения депозитов и
максимальные процентные ставки по вкладам
в банках – до 12% годовых по вкладам в рублях
и до 7% годовых в валюте.
При этом каждый вкладчик получает
дополнительные бонусы. В зависимости от
выбранного вклада, это может быть как
выпуск бесплатной банковской карты MasterCard
для клиента и членов его семьи, а также
бесплатные дополнительные услуги по
картам, так и грандиозный подарок в виде
отдыха в лучших европейских отелях (при
открытии выгодного вклада «Магнус»).
Однако в ближайшее время действующие
ставки по вкладам будут пересмотрены.
Данный шаг продиктован текущей
экономической ситуацией и стремлением
Банка быть в русле рыночных тенденций.
Новые ставки вступят в силу с 1 октября 2013
года, а это значит, что у существующих и
новых клиентов Джей энд Ти Банка осталось
меньше месяца, чтобы успеть открыть
максимально выгодные вклады в надежном
банке по действующим тарифам с высокими
процентами.
На выбор клиентов – широкая линейка
депозитов в рублях и валюте, на срок от трех
месяцев до двух лет, с приятными подарками и
бонусами, а также специальной программой
лояльности «Магнус».
Спешите открыть вклад в Джей энд Ти Банке до
30 сентября и обеспечить себе
гарантированную максимальную прибыль в
следующем году!
Чтобы открыть любой вклад в Джей энд Ти
Банке:
*Приходите в офис Банка по адресу г. Москва,
Кадашевская набережная, дом 26 *Позвоните по
телефону 8 (495) 662-45-45 *Отправьте заявку
электронным письмом на info@jtbank.ru *Заполните
онлайн-заявку на открытие на странице
выбранного вклада *Воспользуйтесь услугой
«Магнус-Экспресс» — откройте вклад онлайн, не
выходя из дома или офиса

Паровоз из памперсов

Коляска и грузовик из подгузников

Что подарить новоиспеченным родителям в честь рождения их малыша? Хочется презентовать что-нибудь особенно милое и одновременно полезное. Коляска или грузовик из подгузников на первый взгляд кажется просто произведением искусства, которое под силу повторить только искусным мастерам. Однако, не боги же горшки обжигают! И для наших рукодельниц нет непосильных задач. Все окажется очень просто, если разобрать общий процесс на пошаговые этапы работы. А мы вам в этом поможем!

Машина из памперсов

Машина из памперсов

Читать