Программирование. Принципы и практика использования C++ Исправленное издание, стр. 349

Итак, каждый раз, проходя цикл, мы оставляем неиспользованную память (“дыру”). Эта память может составлять всего несколько байтов, но если мы не можем использовать их, то это равносильно утечке памяти, а даже малая утечка рано или поздно выводит из строя долговременные системы. Разбиение свободной памяти на многочисленные “дыры”, слишком маленькие для того, чтобы в них можно было разместить объекты, называется фрагментацией памяти (memory fragmentation). В конце концов, механизм управления свободной памятью займет все “дыры”, достаточно большие для того, чтобы разместить объекты, используемые программой, оставив только одну “дыру”, слишком маленькую и потому бесполезную. Это серьезная проблема для всех достаточно долго работающих программ, широко использующих операторы
newdeleteПочему ни язык, ни система не может решить эту проблему? А нельзя ли написать программу, которая вообще не создавала бы “дыр” в памяти? Сначала рассмотрим наиболее очевидное решение проблемы маленьких бесполезных “дыр” в памяти: попробуем переместить все объекты класса
NodeК сожалению, система не может этого сделать. Причина заключается в том, что код на языке С++ непосредственно ссылается на объекты, размещенные в памяти. Например, указатели
n1n2
Теперь мы уплотняем память, перемещаем объекты так, чтобы неиспользуемая память стала непрерывным фрагментом.

Можно, конечно, ответить на вопрос “Где находятся указатели?” для наших структур данных и уплотнить их, но проще вообще избежать фрагментации в начале блока. В данном примере мы могли бы просто разместить оба объекта класса
NodeMessagewhile( ... ) { Node* n1 = new Node; Node* n2 = new Node; Message* p = get_input(dev); // ...храним информацию в узлах... delete p; // ...}Однако перестройка кода для предотвращения фрагментации в общем случае не такая простая задача. Решить ее надежно очень трудно. Часто это приводит к противоречиям с другими правилами создания хороших программ. Вследствие этого мы предпочитаем ограничивать использование свободной памяти только методами, позволяющими избежать фрагментации в начале блока. Часто предотвратить проблему проще, чем ее решить.
ПОПРОБУЙТЕ
Выполните программу, приведенную выше, и выведите на печать адреса и размеры созданных объектов, чтобы увидеть, как возникают “дыры” в памяти и возникают ли они вообще. Если у вас есть время, можете нарисовать схему памяти, подобную показанным выше, чтобы лучше представить себе, как происходит фрагментация.
25.3.2. Альтернатива универсальной свободной памяти
Итак, мы не должны провоцировать фрагментацию памяти. Что для этого необходимо сделать? Во-первых, сам по себе оператор
newdeletedelete
deletenewnew
• Стеки. Стек (stack) — это структура данных, в которой можно разместить любое количество данных (не превышающее максимального размера), причем удалить можно только данные, которые были размещены последними; т.е. стек может расти и уменьшаться только на вершине. Он не вызывает фрагментации памяти, поскольку между двумя его ячейками не может быть “дыр”.
• Пулы. Пул (pool) — это коллекция объектов одинаковых размеров. Мы можем размещать объекты в пуле и удалять их из него, но не можем поместить в нем больше объектов, чем позволяет его размер. Фрагментация памяти при этом не возникает, поскольку объекты имеют одинаковые размеры.