Программирование >>  Синтаксис инициирования исключений 

1 ... 61 62 63 [ 64 ] 65 66 67 ... 82


Переработать старый шаблон MP из предыдущих глав (с операторной функцией operator Type*()), чтобы при выходе из пула и указателей за пределы области действия все необходимое автоматически уничтожалось.

Ниже показан примерный вид полученного интерфейса, с фрагментом клиентского кода и без виртуального оператора =.

В файле foo.h

Подключить объявление чисто абстрактного базового класса #inc1ude pool.h class Foo { private:

Foo(const Foo&) {}

Foo& operator=(const Foo&) { return *this; } public:

static Pool* makePoo1(); Создать пул, оптимизированный для Foo static Foo* make(); Не использует пул

static Foo* make(Poo1*); Использует пул И т.д.

Клиентский код void g(Foo*);

void f() {

MP<Poo1> poo1(Foo::makePoo1()); MP<Foo> foo(Foo::make(poo1));

foo->MemberOfFoo(); Использует операторную функцию operator->() g(foo); Использует операторную функцию operator Type*()

Выход из области действия - удаляется сначала foo, затем pool

Перспективы

Глава заканчивается хорошо - умной, эффективной инкапсуляцией очень сложной проблемы дизайна. Единственным уязвимым местом является вызов функции g() , которая должна пообещать не сохранять долговременный указатель на свой аргумент. Впрочем, подобный анализ необходимо проводить для любой архитектуры, в которой используются временные пулы; в нашем случае ключом является инкапсуляция.

На время забудьте о пулах, временных или иных, и вы увидите разнообразные стратегии применения ведущих указателей для поддержки и инкапсуляции управления памятью в С++.



Основы

управления

памятью


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

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

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

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

Строительные блоки

В числе основных принципов нестандартного управления памятью в С++ должен быть следующий: Придумайте откровенную глупость; вполне возможно, из этого что-нибудь получится . Даже если идея не сработает сама по себе, она может пригодиться в качестве отправной точки.

Поблочное освобождение памяти

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

Фиктивное удаление

Задача многих программ - побыстрее отработать свое и уйти. Это особенно справедливо в среде Unix, где сценарии оболочки объединяют множество крошечных, недолговечных программ. Нередко выделение памяти для новых объектов оказывается самым серьезным фактором, снижающим быстродействие таких программ. Простая стратегия оптимизации заключается в том, что вы выделяете память под объекты снизу вверх большого блока и не удаляете их.

struct Pool {

static Pool* gCurrentPool; Пул для выделения памяти

enum { b1ock size = 8096 }; Выберите свой любимый размер

unsigned char* space; Следующая выделяемая область

size t remaining; Количество оставшихся байт в блоке



Poo1() : space((unsigned char*)ca11oc(b1ock size, \0)),

remaining(b1ock size) {} void* Al1ocate(size t bytes)

if (bytes > b1ock size)

return ::operator new(bytes); Слишком большой запрос if (gCurrentPool == NULL bytes ? remaining)

gCurrentPool = new Pool; void* memory = space; space += bytes; remaining -= bytes; return memory;

class Foo { public:

void* operator new(size t bytes)

if (Poo1::fCurrentPoo1 == NULL)

Poo1::gCurrentPoo1 = new Pool; return Pool::gCurrentPoo1->Al1ocate(bytes);

void operator de1ete(void*) {}

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

Обратите внимание, что для выделения блоков вместо операторной функции ::operator new используется функция ca11oc(). Большинство компиляторов С++ выделяет большой блок с помощью функции ca11oc() (или функции операционной системы), а затем управляет объектами в полученном блоке. Если использовать ::operator new для выделения блоков, скорее всего, дело кончится двойными затратами и двойной фрагментацией, поскольку эти блоки будут существовать в стандартных блоках менеджера памяти. При нашей стратегии лучше обойти ::operator new.

Описанная стратегия также хорошо работает в программах с более продолжительным сроком жизни, которые изначально создают множество объектов некоторого класса, но удаляют их относительно редко (если вообще удаляют). Если операторы new и delete перегружаются на уровне классов, то оптимизацию можно ограничить классами, обладающими указанным свойством.

Сборка мусора на уровне поколений

Многие алгоритмы выглядят примерно так: void Eva1(Structure s)

Создать локальные объекты

Eva1(s.SomePart()); Произвести вычисления для подструктуры Удалить локальные объекты



1 ... 61 62 63 [ 64 ] 65 66 67 ... 82

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика