Как копирующий сборщик мусора обеспечивает отсутствие доступа к объектам во время копирования?

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

Это, очевидно, очень хорошо работает для коллекционеров, останавливающих мир. Однако, поскольку время паузы для Stop-the-world слишком велико, в настоящее время большинство сборщиков мусора позволяют потокам-мутаторам работать одновременно со сборщиком, останавливая мутаторы только на короткое время для выполнения начального сканирования стека.

Итак, как сборщик может гарантировать, что мутатор не получит доступ к «старой» версии объекта во время / после ее копирования? Я предполагаю, что мутаторы могут проверять указатель вперед с каким-то барьером чтения, однако это кажется мне дорогостоящим, поскольку переменные читаются так часто.


person Askaga    schedule 21.01.2013    source источник


Ответы (3)


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

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

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

person Jerry Coffin    schedule 21.01.2013

Барьер загруженного значения, реализованный в сборщике безостановочного мусора Azul Generational, является примером решения этой проблемы. Вы можете прочитать об этом в статье Сборщик мусора Azul, размещенной на InfoQ в начале 2011 года.

person Jan    schedule 21.01.2013
comment
Конечно, Azul не является простым сборщиком полупространств, подобным описанному в вопросе, хотя он действительно перемещает объекты. Если вопрос в том, как простой сборщик полупространств не остановит мир? то я подозреваю, что ответ - не может, но я этого точно не знаю. - person Steve Jessop; 21.01.2013
comment
Описанный алгоритм использует инструкцию своего специализированного оборудования для перехвата доступа на чтение к скопированному объекту. Они говорят, что можно эмулировать их LVB на процессоре x86, добавив несколько инструкций x86. Однако они не говорят ничего конкретного и не дают никаких указаний на производительность. Также я подозреваю, что требуемые инструкции x86, вероятно, значительно увеличат размер кода, что ухудшит производительность кеша инструкций. - person Askaga; 21.01.2013
comment
@BillAskaga: См. Приложение A. В нем не упоминаются конкретные тесты, но он дает веский аргумент, что дополнительные инструкции обычно почти бесплатны для выполнения. К сожалению, они не дают количественной оценки типичной стоимости кода. - person Steve Jessop; 21.01.2013

Отказ от ответственности: это относится только к Shenandoah GC java.

Ваши причины абсолютно точны для Shenandoah! Некоторые подробности, например, здесь.

Не так давно у Shenandoah были барьеры для записи и чтения для всех примитивных и ссылочных типов. Барьер чтения на самом деле был всего лишь одним косвенным обращением через forwarding pointer, как вы предполагаете. Поскольку они намного больше по сравнению с записью (что было гораздо более сложным препятствием), эти барьеры чтения были более дорогими (в совокупности по времени), чем write. Это было связано с тем фактом, что этих чертовски много.

Но, в jdk-13 все изменилось, когда был реализован Load Reference барьер. . Таким образом, только нагрузки имеют барьер, запись происходит обычным способом. Если подумать, это имеет смысл, чтобы писать в поле Object, вам нужно сначала прочитать этот объект, как таковой, если ваш барьер сохраняет " инвариант к пространству ", вы будете всегда читать из самой последней и правильной копии объекта; без необходимости использовать барьер чтения с forwarding pointer.

person Eugene    schedule 02.12.2019