Бьерн Страуструп - Язык программирования С++. Главы 11-13
Страница 58. Сборщик мусора



13.10.1 Сборщик мусора

Сборку мусора можно рассматривать как моделирование бесконечной
памяти на памяти ограниченного размера. Помня об этом, можно
ответить на типичный вопрос: должен ли сборщик мусора вызывать
деструктор для тех объектов, память которых он использует? Правильный
ответ - нет, поскольку, если размещенный в свободной памяти объект
не был удален, то он не будет и уничтожен. Исходя из этого, операцию
delete можно рассматривать как запрос на вызов деструктора (и еще это
- сообщение системе, что память объекта можно использовать). Но как
быть, если действительно требуется уничтожить размещенный в свободной
памяти объект, который не был удален? Заметим, что для
статических и автоматических объектов такой вопрос не встает, -
деструкторы для них неявно вызываются всегда. Далее, уничтожение
объекта "во время сборки мусора" по сути является
операцией с непредсказуемым результатом. Она может совершиться
в любое время между последним использованием объекта и "концом
программы"Ь, а значит, в каком состоянии будет программа в этот момент
неизвестно.

Ь Здесь использованы кавычки, потому что трудно точно определить,
что такое конец программы. (прим. перев.)

Трудно правильно запрограммировать такие операции и они не так полезны,
как кажется.
   Задачу уничтожения объектов, если время этой операции точно не задано,
можно решить с помощью программы обслуживания заявок на уничтожение. Назовем
ее сервером заявок. Если объект необходимо уничтожить в конце программы,
то надо записать в глобальный ассоциативный массив его адрес и
указатель на функцию "очистки". Если объект удален явной операцией,
заявка аннулируется. При уничтожении самого сервера (в конце
программы) вызываются функции очистки для всех оставшихся заявок.
Это решение подходит и для сборки мусора, поскольку мы рассматриваем
ее как моделирование бесконечной памяти. Для сборщика мусора нужно
выбрать одно из двух решений: либо удалять объект, когда единственной
оставшейся ссылкой на него будет ссылка, находящаяся в массиве самого
сервера, либо (стандартное решение) не удалять объект до конца
программы, поскольку все-таки ссылка на него есть.
     Сервер заявок можно реализовать как ассоциативный массив ($$8.8):

         class Register {
             Map<void*, void (*) (void*)> m;
         public:
             insert(void* po, void(*pf)()) { m[po]=pf; }
             remove(void* po) { m.remove(po); }
         };

         Register cleanup_register;

Класс, постоянно обращающийся к серверу, может выглядеть так:

         class X {
           // ...
           static void cleanup(void*);
         public:


          X()
          {
            cleanup_register.insert(this,&cleanup);
            // ...
          }


          ~X() { cleanup(this); }

           // ...
         };

         void X::cleanup(void* pv)
         {
           X* px = (X*)pv;
           cleanup_register.remove(pv);
           // очистка
         }

 Чтобы в классе Register не иметь дела с типами, мы использовали
статическую функцию-член с указателем типа void*.

 
« Предыдущая статья   Следующая статья »