Коллекция на основе трассировки

Опубликовано: 23 Февраля, 2023

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

Алгоритм маркировки и развертки:

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

Алгоритм маркировки и очистки используется виртуальной машиной Java Sun (JVM), которая является стандартной реализацией языка Java. Он существует уже давно и до сих пор выполняет свою работу.

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

Это неэффективно и может замедлить работу вашего приложения. Сборщик мусора поколений был введен для решения этих проблем с помощью алгоритма маркировки и очистки. Вместо того, чтобы собирать все объекты сразу, этот алгоритм собирает объекты в трех разных поколениях или классах: молодое поколение, старое поколение и постоянное поколение.

Сборщики мусора Mark и Compact:

Сборщики мусора Mark и Compact — это тип сборщика мусора, который использует двухэтапный процесс. Первый шаг — пометить все живые объекты, а второй шаг — сжать все мертвые объекты.

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

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

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

Наиболее распространенная форма сбора мусора — это маркировка и уборка. Именно здесь GC анализирует все объекты, чтобы определить, какие из них все еще используются, а какие можно восстановить. Маркировка включает в себя создание ссылки из каждого объекта в памяти на его местоположение в памяти; если объект перемещается из выделенной ему области хранения, то он получает право на удаление или восстановление, либо помечая его как недостижимый (что приводит к тому, что он не учитывается в вашем общем размере кучи), либо помечая его как активный (что приводит к тому, что его ссылки не учитываться против общего размера кучи).

Копирование коллекторов:

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

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

Инкрементальные коллекторы:

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

Точность инкрементной коллекции:

Точность инкрементного сборщика — это процент фактически собранной памяти. Это можно представить как количество байтов, фактически записанных на диск.

Алгоритм используется для определения того, когда память была выделена и освобождена. В некоторых случаях он может учитывать только то, что было выделено для продолжения сборки мусора; в других случаях потребуется больше информации о жизненном цикле каждого объекта, прежде чем решить, следует ли его собирать. Эта разница в требованиях определяет, сколько информации должно храниться о каждом объекте, прежде чем его время жизни будет помечено как недействительное сборщиком мусора (и, следовательно, подходящим для сбора).

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

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

Простая инкрементная трассировка:

Еще один базовый метод сбора мусора — трассировка указателей в программе. Это можно сделать, добавив код в компилятор, или это можно сделать вручную как часть внешнего интерфейса вашего компилятора. Когда используется указатель, мы можем записать его адрес, чтобы позже, когда мы будем отслеживать сборку мусора, мы знали, какие части были собраны, а какие нет.

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

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

Частичные коллекторы (алгоритм поезда):

Алгоритм поезда представляет собой сборщик с частичным копированием. Мы рассмотрим алгоритм поезда, который используется для сбора мусора по поколениям.

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

В этом разделе мы сосредоточимся на том, как работает подсчет ссылок, чтобы понять, как частичный сбор работает в этом контексте.

Подсчет ссылок — это простой и эффективный способ отслеживания количества ссылок на объект. Как только число достигает нуля, оно может быть освобождено и доступно для повторного использования. В этом контексте «ссылка» означает любую переменную, содержащую ссылку на объект.

Сюда входят локальные переменные, глобальные переменные и параметры, передаваемые функциям. Подсчет ссылок может быть реализован двумя способами: первый — «инкрементный», когда каждая операция, создающая ссылку, увеличивает счетчик ссылок на единицу; когда объект освобождается, его счетчик ссылок уменьшается на единицу. Второй метод, используемый Python, известен как «поколенческий». Каждый раз, когда создается ссылка, она назначается поколению в зависимости от того, как давно она была создана. Поколения обычно нумеруются от 0 до N-1, где N — допустимое количество поколений. Когда счетчик ссылок на объект достигает нуля (это означает, что больше нет ссылок на этот объект), все экземпляры этого поколения собираются и полностью удаляются из памяти.