Фрагментация памяти - это та же концепция, что и фрагментация диска: она относится к неиспользуемому пространству, поскольку используемые области недостаточно плотно упакованы.
Предположим, что для простого примера игрушки у вас есть десять байтов памяти:
| | | | | | | | | | |
0 1 2 3 4 5 6 7 8 9
Теперь давайте выделим три трехбайтовых блока с именами A, B и C:
| A | A | A | B | B | B | C | C | C | |
0 1 2 3 4 5 6 7 8 9
Теперь освободим блок B:
| A | A | A | | | | C | C | C | |
0 1 2 3 4 5 6 7 8 9
Что произойдет, если мы попытаемся выделить четырехбайтовый блок D?Ну, у нас есть четыре байта свободной памяти, но у нас нет четырех смежных свободных, поэтому мы не можем выделить D!Это неэффективное использование памяти, потому что мы должны были хранить D, но мы не смогли.И мы не можем переместить C, чтобы освободить место, потому что очень вероятно, что некоторые переменные в нашей программе указывают на C, и мы не можем автоматически найти и изменить все эти значения.
Откуда вы знаете, что этопроблема?Ну, самый большой признак в том, что размер виртуальной памяти вашей программы значительно больше, чем объем памяти, который вы фактически используете.В реальном примере у вас было бы намного больше, чем десять байтов памяти, поэтому D просто выделялся бы, начиная с байта 9, а байты 3-5 оставались бы неиспользованными, если позже вы не выделите что-нибудь длиной три байта или меньше.
В этом примере 3 байта - это не целая трата, но рассмотрим более патологический случай, когда два выделения по пару байтов, например, разделяют десять мегабайт в памяти, и вам нужно выделитьблок размером 10 мегабайт + 1 байт.Вы должны попросить у ОС больше, чем на десять мегабайт, виртуальной памяти, чтобы сделать это, даже если вам не хватает места уже на один байт.
Как это предотвратить?Наихудшие случаи, как правило, возникают, когда вы часто создаете и уничтожаете небольшие объекты, поскольку это имеет тенденцию вызывать эффект «швейцарского сыра», когда множество мелких объектов разделено множеством маленьких отверстий, что делает невозможным размещение более крупных объектов в этих отверстиях.Когда вы знаете, что собираетесь делать это, эффективная стратегия состоит в том, чтобы предварительно выделить большой блок памяти в качестве пула для ваших небольших объектов, а затем вручную управлять созданием небольших объектов в этом блоке, вместо того, чтобыобработчик по умолчанию обрабатывает его.
В общем, чем меньше выделений вы делаете, тем меньше вероятность фрагментации памяти.Однако STL справляется с этим довольно эффективно.Если у вас есть строка, использующая все ее текущее размещение, и вы добавляете к ней один символ, она не просто перераспределяет ее текущую длину плюс одну, она удваивает ее длину.Это вариант стратегии «пул для частых небольших выделений».Строка захватывает большой кусок памяти, так что она может эффективно справляться с многократным небольшим увеличением размера без повторных небольших перераспределений.Все контейнеры STL на самом деле делают такие вещи, поэтому обычно вам не нужно слишком беспокоиться о фрагментации, вызванной автоматически перераспределяемыми контейнерами STL.
Хотя, конечно, контейнеры STL не объединяют память между друг другом, поэтому, если вы собираетесь создать много небольших контейнеров (а не несколько контейнеров, размер которых часто изменяется), вы можетеВы должны заботиться о предотвращении фрагментации таким же образом, как и для любых часто создаваемых мелких объектов, STL или нет.