Ответ
Фрагментация кучи — это состояние динамической памяти (кучи), при котором свободное пространство разбито на множество небольших, несмежных блоков. В результате невозможно выделить один большой непрерывный блок памяти, даже если общий объем свободной памяти достаточен.
Основные причины в C++:
- Частые и разноразмерные вызовы
new/deleteилиmalloc/free. - Неоптимальная стратегия работы аллокатора стандартной библиотеки.
- Длительная работа программы с "рваным" паттерном выделения/освобождения.
Прямой пример на C++:
int* block1 = new int[100]; // Выделен блок A
int* block2 = new int[200]; // Выделен блок B
int* block3 = new int[50]; // Выделен блок C
delete[] block1; // Освобождается блок A
// Теперь в куче есть свободный блок на 100 int, но он расположен между занятыми блоками B и C.
// Попытка выделить блок на 150 int может завершиться неудачей (std::bad_alloc),
// несмотря на то, что суммарно свободно 100 + 50 (если освободить C) = 150 элементов.
int* block4 = new int[150]; // Может вызвать ошибку из-за фрагментации.
Последствия:
- Сбои выделения памяти (
std::bad_alloc) при, казалось бы, достаточном свободном месте. - Увеличение времени на поиск подходящего блока аллокатором.
- Рост общего потребления памяти (оверхеда) из-за служебных структур.
Способы борьбы в C++:
- Использование специализированных аллокаторов:
std::pmr::memory_resource(C++17) с пулами (std::pmr::synchronized_pool_resource). - Выделение памяти крупными "страницами" с последующим ручным управлением внутри приложения.
- Минимизация количества динамических выделений: использование контейнеров с
reserve(), стековых объектов,std::make_shared(который часто выделяет блок для объекта и контрольного блока вместе). - Использование компактных структур данных, избегающих указателей на множество мелких объектов.