
496
Глава 5. Вычисления на регистровых машинах
Реализация сборщика мусора методом остановки с копированием
Теперь мы можем с помощью языка регистровых машин описать алгоритм останов-
ки с копированием более подробно. Предположим, что имеется регистр root, и в нем
хранится указатель на корневой объект — структуру, которая (через перенаправления)
указывает на все доступные данные. Такой конфигурации можно добиться, если переме-
стить содержимое всех регистров машины в заранее выделенный список, на который и
будет указывать root, непосредственно перед запуском сборщика мусора
16
. Кроме то-
го, мы предполагаем, что помимо текущей рабочей памяти имеется свободная память, в
которую мы можем копировать используемые дан ные. Текущая рабочая память состоит
из векторов, базовые адреса которых хран ятся в регистрах the-cars и the-cdrs, а
свободная память доступна через регистры new-cars и new-cdrs.
Сборка мусора запускается, когда кончаются свободные ячейки в текущей рабочей
памяти, то есть когда операция cons пытается сдвинуть указатель free за преде лы
вектора памяти. По завершении сборки мусора указатель root будет указывать на но-
вую память, все объекты, дос ту пные через root, будут перемещены в новую память, а
указатель free будет указывать на место в новой памяти, начиная с которого можно вы-
делять новые пары. Кроме того, поменяются местами роли рабочей памяти и свободной
памяти — новые пары будут выде ляться в новой памяти, начиная с места, на кото-
рое показывает free, а (предыдущая) рабочая память будет доступна в качестве новой
памяти для следующей сборки мусора. На рисунке 5.15 показано устройство памяти
непосредствен но перед сборкой мусора и сразу после нее.
Состояние процесса сборки мусора управляется содержимым двух регистров: free и
scan. Оба они сначала указывают на начало новой памяти. При запуске алгоритма пара,
на которую указывает root, переносится в начало новой памяти. Пара копируе тся, ре-
гистр root переставляется в новое место, а указатель free у величивается на единицу.
В дополнение к этому в старом месте, где хранилась пара, делается пометка, которая
говорит, что содержимое перенесено. Отметка делается так: в позицию car м ы помеща-
ем особое значение, показывающее , что объект перемещен. (По традиции, такой о бъект
называется разбитое сердце (broken heart).)
17
В позицию cdr мы помещаем перена-
правляющий адрес (forwarding address), который указывает на место, куда перемещен
объект.
После того, как перемещен корневой объект, сборщик мусора входит в основной
цикл. На каждом шаге алгоритма регистр scan (вначале он указывает на перемещенный
корневой объект) содержит адрес пары, которая сама перемещена в новую память, но
car и cdr которой по-прежнему указывают на объекты в старой памяти. Каждый из
этих объектов перемещается, а затем регистр scan увеличивается на единицу. При
перемещении объекта (например, того, на который указывает car сканируемой пары)
мы прежде всего проверяем, не перемещен ли он уже (об этом нам говорит разбитое
очистки должна проверять всю память. Второе преимущество остановки с копированием состоит в том, что это
сжимающий (compacting) сборщик мусора. Это означает, что в конце фазы сборки мусора все используемые
данные оказываются в последовательной области памяти, а весь мусор «выжат». На машинах с виртуаль-
ной памятью это может давать весьма большой выигрыш в производительности, поскольку доступ к сильно
различающимся адресам в памяти может приводить к дополнительной подкачке страниц.
16
Этот список регистров не включает в себя регистры, которые используются подсистемой выделения памя-
ти — root, the-cars, the-cdrs и еще несколько регистров, которые будут введены в этом разделе.
17
Термин разбитое сердце придумал Дэвид Кресси , когда он писал сборщик мусора для MDL, диалекта
Лиспа, разработанного в MIT в начале 70-х годов.