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*.


Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.