Почему не работает циклический сборщик

Тема: Не улучшайте циклический сборщик!

Опции темы
Поиск по теме
Отображение

Не улучшайте циклический сборщик!

Важная информация для игроков! Госпада не тратьте лишние ресурсы!

Многоуважаемая администрация недавно порезала скорость работы циклических сборщиков, но сделано это очень «интересным» путем. Была изменена не скорость процесса сбора, а время между сборками. Что это означает для игроков. А это значит что не имеет значения первый у вс сборщик стоит или сборщик прогрейженный до резонирующей рамки со всем ускоряторами. Скорость работы этих двух сборщиков будет совершенно одинаковой. Ускоряторы меняют скорость работы, а не время между циклами сборки.

Говорю это не голословно, только что встал перед сборщиком(грейжен до синалового), вставил в него 2 ускорятора, посмотрел на скорость, вытащил 2 ускорятора и. Не изменилось вообще ничего! Вот вообще. Так что не переводите жемчуг эндера на этот механизм.

Спасибо за внимание и спасибо администрации за заботу об игроках!

Я понимаю, что администрация стремится тим изменением замедлить развитие игроков. Что ж. пойду потрачу лишние 10 минут на крафт ещё пары тройки сборщиков, что бы добиться нужной мне скорости.

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

Поставил 2 сборщика с ускоряторами и без них. Загрузил одинаковое количество материала. Поставил к каждому по сундуку и запустил их рычагом одновременно. Потом через минуту выключил рычаг и проверил содержимое сундуков. Поровну! И не просто примерно поровну, а абсолютно одинаково.

Читайте также:  Почему не работает водонагреватель zanussi

Так что. НЕ ИСПОЛЬЗУЙТЕ УСЛИЛЕННЫЕ И ТАК ДАЛЕЕ СБОЩИКИ! ПУСТАЯ ТРАТА РЕСУРСОВ.

Последний раз редактировалось Seregawithapple; 10.01.2017 в 14:48 .

Источник

Всё, что нужно знать о сборщике мусора в Python

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

Менеджер памяти

В отличие от других популярных языков, Python не освобождает всю память обратно операционной системе как только он удаляет какой либо объект. Вместо этого, он использует дополнительный менеджер памяти, предназначенный для маленьких объектов (размер которых меньше чем 512 байт). Для работы с такими объектами он выделяет большие блоки памяти, в которых в дальнейшем будет хранится множество маленьких объектов.

Как только один из маленьких объект удаляется — память из под него не переходит операционной системе, Python оставляет её для новых объектов с таким же размером. Если в одном из выделенных блоков памяти не осталось объектов, то Python может высвободить его операционной системе. Как правило, высвобождение блоков случается когда скрипт создает множество временных объектов.

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

Алгоритмы сборки мусора

Стандартный интерпретатор питона (CPython) использует сразу два алгоритма, подсчет ссылок и generational garbage collector (далее GC), более известный как стандартный модуль gc из Python.

Алгоритм подсчета ссылок очень простой и эффективный, но у него есть один большой недостаток. Он не умеет определять циклические ссылки. Именно из-за этого, в питоне существует дополнительный сборщик, именуемый поколенческий GC, который следит за объектами с потенциальными циклическими ссылками.

В Python, алгоритм подсчета ссылок является фундаментальным и не может отключен, тогда как GC опционален и может быть отключен.

Алгоритм подсчета ссылок

Алгоритм подсчета ссылок это одна из самых простых техник для сборки мусора. Объекты удаляются как только на них больше нет ссылок.

В Python, переменные не хранят значения, а выступают в роли ссылок на объекты. То есть когда вы присваивайте значение новой переменной, то сначала создается объект с этим значением, а уже потом переменная начинает ссылаться на него. На один объект может ссылаться множество переменных.

Каждый объект в Python содержит дополнительное поле (счетчик ссылок), в котором хранится количество ссылок на него. Как только кто-то ссылается на объект, это поле увеличивается на единицу. Если по какой-то причине ссылка пропадает, то это поле уменьшается на один.

Примеры, когда количество ссылок увеличивается:

  • оператор присваивания
  • передача аргументов
  • вставка нового объекта в лист (увеличивается количество ссылок для объекта)
  • конструция вида foo = bar (foo начинается ссылаться на тот же объект, что и bar)

Как только счетчик ссылок для определенного объекта достигает нуля интерпретатор запускает процесс уничтожения объекта. Если удаленный объект содержал ссылки на другие объекты, то эти ссылки также удаляются. Таким образом, удаление одного объекта может повлечь за собой удаление других.

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

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

Переменные, которые объявлены внутри блока (функции, класса) имеют локальную видимость (т.е. они видны только внутри блока). Как только интерпретатор питона выходит из блока он уничтожает все ссылки созданные локальными переменными внутри него.

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

Пример работы счетчика ссылок:

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

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

Дополнительный сборщик мусора

Зачем нам нужен дополнительный алгоритм, когда у нас уже есть подсчет ссылок?

К сожалению, классический алгоритм подсчета ссылок имеет один большой недостаток — он не умеет находить циклические ссылки. Циклические ссылки происходят когда один или более объектов ссылаются на друг друга.

Как вы можете видеть, объект lst ссылается сам на себя, тогда как object1 и object2 ссылаются друг на друга. Для таких объектов счетчик ссылок всегда будет равен 1.

Демонстрация на Python:

В примере выше, инструкция del удаляет ссылки на наши объекты (не сами объекты). Как только Python выполняет инструкцию del эти объекты становятся недоступны из Python кода. Однако, с выключенным модулем gc они по прежнему будут оставаться в памяти, т.к. они имели циклические ссылки и их счетчик по прежнему равен единице. Вы можете визуально исследовать такие связи используя библиотеку objgraph .

Для того, чтобы исправить эту проблему, в Python 1.5 был добавлен дополнительный алгоритм, известный как модуль gc. Единственная задача которого удаление циклических объектов, к которым уже нет доступа из кода.

Циклические ссылки могут происходить только в “контейнерных” объектах. Т.е. в объектах, которые могут хранить другие объекты, например в списках, словарях, классах и кортежах. GC не следит за простыми и неизменяемыми типами, за исключением кортежей. Некоторые кортежи и словари так же исключаются из списка слежки при выполнении определенных условий. Со всеми остальными объектами гарантированно справляется алгоритм подсчета ссылок.

Когда GC срабатывает

В отличие от алгоритма подсчета ссылок, циклический GC не работает в режиме реального времени и запускается периодически. Каждый запуск сборщика создаёт микропаузы в работе кода, поэтому CPython (стандартный интерпретатор) использует различные эвристики, для определения частоты запуска сборщика мусора.

Циклический сборщик мусора разделяет все объекты на 3 поколения (генерации). Новые объекты попадают в первое поколение. Если новый объект выживает процесс сборки мусора, то он перемещается в следующее поколение. Чем выше поколение, тем реже оно сканируется на мусор. Так-как новые объекты зачастую имеют очень маленький срок жизни (являются временными), то имеет смысл опрашивать их чаще, чем те, которые уже прошли через несколько этапов сборки мусора.

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

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

Стандартные пороги срабатывания для поколений установлены на 700, 10 и 10 соответственно, но вы всегда можете их изменить с помощью функций gc.get_threshold и gc.set_threshold .

Алгоритм поиска циклов

Для полноценного описания алгоритма поиска циклов потребуется отдельная статья. Если кратко, то GC итерирует каждый объект из выбранных поколений и временно удаляет все ссылки от отдельно взятого объекта (все ссылки на которые этот объект ссылается). После полного прохода, все объекты, у которых счетчик ссылок меньше двух считаются недоступными из питона и могут быть удалены.

Для более глубокого понимания я рекомендую прочитать (прим. переводчика: английский материал) оригинальное описание алгоритма от Neil Schemenauer и функцию collect из исходников CPython. Описание из Quora и пост о сборщике мусора так же могут быть полезны.

Стоит отметить, что проблема с деструкторами описанная в оригинальном описании алгоритма была исправлена начиная с Python 3.4 (подробнее в PEP 442).

Советы по оптимизации

Циклы зачастую случаются в реальных задачах, их можно встретить в задачах с графами, связными списками или в структурах данных, где требуется вести учёт отношений между объектами. Если ваша программа имеет высокую нагрузку и требовательна к задержкам, то, по возможности, циклы лучше избегать.

В местах, где вы заведомо используйте циклические ссылки, можно использовать «слабые» ссылки. Слабые ссылке реализованы в модуле weakref и в отличие от обычных ссылок никак не влияют на счётчик ссылок. Если объект со слабой ссылок оказывается удалённым, то вместо него возвращается None .

В некоторых случаях полезно отключить автоматическую сборку модулем gc и вызывать его вручную. Для этого достаточно вызывать gc.disable() и в дальнейшем вызывать gc.collect() вручную.

Как найти и отладить циклические ссылки

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

Модуль gc предоставляет вспомогательные функции, которые могут помочь в отладке. Если параметры GC установить на флаг DEBUG_SAVEALL , то все недоступные объекты будут добавлены в список gc.garbage .

Как только вы определите проблемное место — его можно визуализировать с помощью objgraph.

Заключение

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

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

Источник

Сборщик мусора в среде .NET

Здравствуйте, Великие и Ужасные хабражители!
Как я недавно узнал, не так много народу знает о том, как работает сборщик мусора. Хотя я понимаю, что 99% разработчиков это не особо нужно, но я хотел бы, чтобы все, кто разрабатывают приложения на .NET, знали принцип его работы. В этой статье я постараюсь вкратце рассказать, как собственно работает сборщик мусора.

Базовые сведения о времени жизни объекта

Размещайте объект в управляющей куче с помощью ключевого слова new и забывайте об этом.

После создания объект будет автоматически удалён сборщиком мусора, когда в нём отпадёт надобность. Сразу возникает вопрос о том, каким образом сборщик мусора определяет, когда в объект отпадает необходимость?

Давайте просмотрим простой пример:

Обратите внимание, что ссылка на объект Car(myCar) была создана непосредственно внутри метода MakeACar() и не передавалась за пределы определяющей области действия (ни в виде возвращающегося значения, ни в виде параметров ref/out). По этому после вызова метода ссылка на myCar окажется недостижимой, а объект Car — кандидатом на удаление сборщиком мусора. Следует, однако, понимать, что нет никакой гарантии на удаление объекта сразу после выполнение метода MakeACar(). Всё, что в данный момент можно предполагать, так это то, что когда в CLR-среде будет в следующий раз проводиться сборка мусора, то объект myCar будет поставлен на удаление.

Программистам на C++ хорошо известно, что если они специально не позаботятся об удалении размещённых в куче объектов, вскоре обязательно начнут возникать «утечки памяти». На самом деле отслеживание проблем, связанных с проблемой утечки памяти, являются одним из самых утомительных и длинных аспектов программирования в неуправляемых средах.

Роль корневых элементов приложения

Чтобы разобраться, каким образом сборщик мусора определяется, когда объект уже не нужен, необходимо знать, что собой представляют корневые элементы приложения (application roots). Попросту говоря, корневым элементом (root) называется ячейка в памяти, в которой содержится ссылка на размещающийся в куче объект. Строго говоря, корневыми могут называться элементы:

  • Ссылки на глобальные объекты (хотя в C# они не разрешены, CIL-код позволяет размещать глобальные объекты
  • Ссылки на любые статические объекты или статические поля.
  • Ссылки на локальные объекты в пределах кодовой базы приложения.
  • Ссылки на передаваемые методу параметры объекта.
  • Ссылки на объект, ожидающий финализации.
  • Любые регистры центрального процессора, которые ссылаются на объект.

Во время процессы сборки мусора исполняющая среда будет исследовать объекты в куче, чтобы определить, являются ли они по прежнему достижимыми (т.е. корневыми) для приложения. Для этого среда CLR будет создавать графы объектов, представляющие все достижимые для приложения объекты. Кроме того, следует иметь ввиду, что сборщик мусора никогда не будет создавать граф для одного и того же объекта дважды, избегая необходимости выполнения подсчёта циклических ссылок, который характерен для программирования в среде COM.

Поколения объектов

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

Например, класс, определённый в главном окне настольного приложения, будет оставаться в памяти вплоть до завершения программы. С другой стороны, объект, попавший в кучу совсем недавно (например те, что находятся в области видимости методов), вероятнее всего будут становиться недостижимыми достаточно быстро. Изводя из этих предположений, каждый объект в куче относится к:

  • Поколение 0. Идентифицируется новый только что размещённый объект, который ещё никогда не помечался как надлежащий удалению в процессе сборки мусора
  • Поколение 1. Идентифицирует объект, который уже «пережил» один процесс сборки мусора (был помечен, как надлежащий удалению, но не был удалён из-за достаточного свободного места в куче).
  • Поколение 2. Идентифицирует объект, который пережил более одного прогона сбора мусора

Поколения 0 и 1 называются эфемерными.

Сборщик мусора сначала анализирует все объекты, которые относятся к поколению 0. Если после их удаления остаётся достаточное количество памяти, статус всех уцелевших объектов повышается до поколения 1. Если все объекты поколения 0 были проверены, но всё равно требуется дополнительное пространство, то будет запцщени проверка объектов поколения 1. Объекты этого поколения, которым удалось уцелеть, станут объектами поколения 2. если же сборщику мусора всё равно понадобится память, что сборке мусора подвергнуться объекты поколения 2. Так как объектов выше 2 поколения не бывает, то статус объектов не изменится.
Из всего вышесказанного можно сделать вывод, что более новые объекты будут удалятся быстрее, нежели более старые.

Параллельная сборка мусора в .NET 1.0 — .NET 3.5

До выхода .NET 4.0 очистка неиспользуемых объектов проводилась с применением техники параллельной сборки мусора. В этой модели при выполнении сбора мусора эфемерных объектов сборщик мусора временно приостанавливал все активные потоки внутри текущего процесса, чтобы приложение не могло получить доступ к управляемой куче вплоть до завершения процесса сборки мусора.
По завершению цикла сборки мусора приостановленным потокам разрешалось снова продолжить работу. К счастью, в .NET 3.5 сборщик мусора был хорошо оптимизирован и потому связанные с ним короткие перерывы в работе с приложением редко становились заметными.
Как и оптимизация, параллельная сборка мусора позволяла проводить очистку объектов, которые не были обнаружены ни в одном из эфемерных поколений, в отдельном потоке. Это сокращало (но не устраняло) необходимость в приостановке активных потоков исполняющей средой .NET. Тем более, параллельная сборка мусора позволяла размещать объекты в куче во время сборки объектов не эфемерных поколений.

Фоновая сборка мусора в .NET 4.0

И напоследок я хотел бы вам рассказать об улучшении работы сборщика мусора в .NET 4.0.

В .NET 4.0 сборщик мусора по-другому решает вопрос о приостановке потоков и очистке объектов в управляемой куче, используя при этом технику фоновой сборки мусора. Не смотря на её название, это вовсе не означает, что вся сборка мусора теперь происходит в дополнительных фоновых потоках выполнения. На самом деле в случае фоновой сборки мусора для объектов, не относящихся к эфемерному поколению, исполняющая среда .NET теперь может проводить сборку мусора объектов эфемерного поколения в отдельном фоновом потоке.
Механизм сборки мусора в .NET 4.0 был улучшен так, чтобы на приостановку потока, связанного с деталями сбора мусора, требовалось меньше времени. Благодаря этим изменениям, процесс очистки неиспользуемых объектов поколения 0 и 1 стал оптимальным. Он позволяет получать более высокий уровень производительности приложений.

Источник

Оцените статью