Фрагментация памяти требует предварительного знания о распределении памяти, поэтому мне нужно сначала установить некоторые понятия.
Выделение памяти
Когда вы вызываете оператор new
(который по умолчанию будет часто вызывать malloc
за кулисами), вы напрямую не запрашиваете память у ОС, вместо этого (как правило) происходит следующее:
- вы вызываете
malloc
для 76 байтов, он выглядит, если таковой имеется: - , если это не так, он запрашивает страницу (обычно 4 КБ) из ОС, и подготовит это
- он затем обслуживает 76 байтов, которые вы запрашивали
Фрагментация памяти может происходить на двух уровнях:
- Вы можете исчерпать свое виртуальное адресное пространство (не так просто с64-битные платформы)
- У вас могут быть почти пустые страницы, которые не могут быть восстановлены и, тем не менее, не могут обслуживать ваши запросы
Как правило, поскольку malloc
должен вызывать страницы по 4 КБ за раз (если вы не попросите больший кусок в этом случаеон выберет большее 4KB), вы никогда не должны исчерпывать свое адресное пространство.Это произошло на 32-битной машине (ограничено 4 ГБ) для необычно больших выделений.
С другой стороны, если ваша реализация malloc
слишком наивна, вы можете получить фрагментированные блоки памяти и, таким образом, иметьгораздо больше памяти, чем то, что вы действительно используете.Обычно это то, к чему относится термин фрагментация памяти .
Типичная стратегия
Когда я говорю наивный Я имею в видунапример, к вашей идее распределять все непрерывно.Это плохая идея.Как правило, это , а не , что происходит.
Вместо этого хорошие реализации malloc
сегодня используют пулы.
Как правило, они будут иметь пулы на размер * 1054.*:
- 1 байт
- 2 байта
- 4 байта
- ...
- 512 байтов
- ...
- 4 КБ и более обрабатываются специально (напрямую)
И когда вы делаете запрос, они находят пул с минимальным размером, который может его удовлетворить,и этот пул будет служить вам.
Поскольку в пуле все запросы обслуживаются с одинаковым размером, в пуле нет фрагментации, так как для любого входящего запроса можно использовать ячейку free ..
Итак, фрагментация?
В настоящее время вы не должны наблюдать фрагментацию как таковую.
Однако вы все еще можете наблюдать дыры в памяти.Предположим, что пул обрабатывает объекты размером от 9 до 16 байтов, и вы выделяете, скажем, 4 000 000 из них.Для этого требуется не менее 16 000 страниц размером 4 КБ.Теперь предположим, что вы освободили все, кроме 16 000 из них, но коварно, так что один объект все еще живет для каждой страницы.Страницы не могут быть восстановлены ОС, так как вы все еще используете их, однако, поскольку вы используете только 4 байта из 4 КБ, пространство довольно потрачено (пока).
Некоторые языки с сборкой мусора могут обрабатывать этив случаях сжатие , однако в C ++ перемещение объекта в памяти не может быть выполнено, поскольку пользователь имеет прямой контроль над адресами объектов.
Волшебный контейнер
Я не знаю ни одного такого зверя.Я тоже не понимаю, почему это было бы полезно.
TL; DR
Не беспокойтесь о фрагментации.
Примечание:«Эксперты» могут захотеть написать собственный механизм распределения пула, я хотел бы напомнить им, чтобы они не забывали о выравнивании