Бьерн Страуструп. Язык программирования С++



бет123/124
Дата16.07.2016
өлшемі3.27 Mb.
#204081
түріКнига
1   ...   116   117   118   119   120   121   122   123   124

13.10 Управление памятью


При проектировании библиотеки или просто программы с большим временем

счета один из ключевых вопросов связан с управлением памятью.

В общем случае создатель библиотеки не знает, в каком окружении она

будет работать. Будет ли там ресурс памяти настолько критичен, что ее

нехватка станет серьезной проблемой, или же серьезной помехой станут

накладные расходы, связанные с управлением памятью?

Один из основных вопросов управления памятью можно сформулировать

так: если функция f() передает или возвращает указатель на объект, то

кто должен уничтожать этот объект? Необходимо ответить и на связанный

с ним вопрос: в какой момент объект может быть уничтожен? Ответы на эти

вопросы особенно важны для создателей и пользователей таких контейнеров,

как списки, массивы и ассоциативные массивы. С точки зрения

создателя библиотеки идеальными будут ответы: "Система" и "В тот момент,

когда объект больше никто не использует". Когда система уничтожает

объект, обычно говорят, что она занимается сборкой мусора, а та часть

системы, которая определяет, что объект больше никем не используется,

и уничтожает его, называется сборщиком мусора.

К сожалению, использование сборщика мусора может повлечь за собой

накладные расходы на время счета и память, прерывания полезных

функций, определенную аппаратную поддержку, трудности связывания

частей программы на разных языках или просто усложнение системы.

Многие пользователи не могут позволить себе этого.Ь
Ь Говорят, что программисты на Лиспе знают, насколько важно управление

памятью, и поэтому не могут отдать его пользователю. Программисты

на С тоже знают, насколько важно управление памятью, и поэтому не

могут оставить его системе.


Поэтому в большинстве программ на С++ не приходится рассчитывать

на сборщик мусора и нужно предложить свою стратегию размещения

объектов в свободной памяти, не обращаясь к системе. Но реализации

С++ со сборщиком мусора все-таки существуют.

Рассмотрим самую простую схему управления памятью для программ

на С++. Для этого заменим operator new() на тривиальную функцию

размещения, а operator delete() - на пустую функцию:
inline size_t align(size_t s)

/*

Даже в простой функции размещения нужно



выравнивание памяти, чтобы на объект

можно было настроить указатель

произвольного типа

*/

{



union Word { void* p; long double d; long l; }
int x = s + sizeof(Word) - 1;

x -= x%sizeof(Word);

return x;

}
static void* freep; // настроим start на свободную память


void* operator new(size_t s) // простая линейная функция размещения

{

void* p = freep;



s = align(s);

freep += s;

return p;

}
void operator delete(void*) { } // пусто


Если память бесконечна, то наше решение дает сборщик мусора без

всяких сложностей и накладных расходов. Такой подход не применим

для библиотек, когда заранее неизвестно, каким образом будет

использоваться память, и когда программа, пользующаяся библиотекой,

будет иметь большое время счета. Такой способ выделения памяти

идеально подходит для программ, которым требуется ограниченный объем

памяти или объем, пропорциональный размеру входного потока данных.

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


Сборку мусора можно рассматривать как моделирование бесконечной

памяти на памяти ограниченного размера. Помня об этом, можно

ответить на типичный вопрос: должен ли сборщик мусора вызывать

деструктор для тех объектов, память которых он использует? Правильный

ответ - нет, поскольку, если размещенный в свободной памяти объект

не был удален, то он не будет и уничтожен. Исходя из этого, операцию

delete можно рассматривать как запрос на вызов деструктора (и еще это

- сообщение системе, что память объекта можно использовать). Но как

быть, если действительно требуется уничтожить размещенный в свободной

памяти объект, который не был удален? Заметим, что для

статических и автоматических объектов такой вопрос не встает, -

деструкторы для них неявно вызываются всегда. Далее, уничтожение

объекта "во время сборки мусора" по сути является

операцией с непредсказуемым результатом. Она может совершиться

в любое время между последним использованием объекта и "концом

программы"Ь, а значит, в каком состоянии будет программа в этот момент

неизвестно.


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

что такое конец программы. (прим. перев.)


Трудно правильно запрограммировать такие операции и они не так полезны,

как кажется.

Задачу уничтожения объектов, если время этой операции точно не задано,

можно решить с помощью программы обслуживания заявок на уничтожение. Назовем

ее сервером заявок. Если объект необходимо уничтожить в конце программы,

то надо записать в глобальный ассоциативный массив его адрес и

указатель на функцию "очистки". Если объект удален явной операцией,

заявка аннулируется. При уничтожении самого сервера (в конце

программы) вызываются функции очистки для всех оставшихся заявок.

Это решение подходит и для сборки мусора, поскольку мы рассматриваем

ее как моделирование бесконечной памяти. Для сборщика мусора нужно

выбрать одно из двух решений: либо удалять объект, когда единственной

оставшейся ссылкой на него будет ссылка, находящаяся в массиве самого

сервера, либо (стандартное решение) не удалять объект до конца

программы, поскольку все-таки ссылка на него есть.

Сервер заявок можно реализовать как ассоциативный массив ($$8.8):


class Register {

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





Достарыңызбен бөлісу:
1   ...   116   117   118   119   120   121   122   123   124




©dereksiz.org 2024
әкімшілігінің қараңыз

    Басты бет