Не правильно ли удалены фрагменты памяти указателей?
Нет. Множество выделений и выпусков памяти будут фрагментировать память.
Вот интуитивнообъяснение распределения памяти (оно более сложное, и мой пример в лучшем случае наивен и игнорирует множество проблем, но должно дать вам некоторое представление).
Распределение памяти обычно происходит в (по крайней мере) двухшаги:
ОС выделяет блоки памяти для приложения.
Приложение выделяет память из доступных блоков для собственного использования.
Если приложение использует всю доступную память (или больше не может выделять), ОС выделит приложению больше памяти.Это делается прозрачно для приложения, но требует времени (поэтому выделение памяти происходит медленно).
Когда приложение освобождает память, адреса / блоки помечаются как свободные и будут повторно использоваться в последующих запросах выделения (new / malloc / realloc / etc) приложением.
Фрагментация памяти происходит, когда блоки памяти, выделенные для приложения, становятся фрагментированными (некоторые фрагменты выделены, а некоторые свободны).
Например:
int *a = new int;
int *b = new int;
int *c = new int;
int *d = new int;
int *e = new int;
int *f = new int;
// if the memory blocks for the pointers were allocated contiguously,
// the heap will look like this:
// [ a ][ b ][ c ][ d ][ e ][ f ][ free memory ... ]
// sometime later:
delete b;
delete d;
delete e;
// same memory block will look like this:
// [ a ][free][ c ][free][free][ f ][ free memory ... ]
Ради простоты предположим, что ваше приложение запускается с доступной 1000 байтов памяти).Если на первом шаге вы выделите 200 int*
(200 различных переменных), у вас будет выделено 200 x 4 = 800 байт, 200 байт свободно.
Если вы хотите выделить (на втором шаге) new int[100]
больше (один указатель, еще 400 байтов), вам не хватит памяти, и приложение должно будет запросить больше у ОС.Вам понадобится не менее 200 байт в текущем блоке или новый блок не менее 400 байт из ОС).
Если вы удалили память, выделенную на шаге 1, чтобы освободить место для выделения на шаге 2, было бы важно, какую память вы удалили:
Если вы удалили последние выделенные указатели - вам нужно удалить последние 50 указателей (50x4 = 200) - у вас будетОсвобождено 200 байт + 200 без локализации = необходимо 400). OK
Если вы удалите каждый второй указатель, выделенный на шаге 1 (или первые 50 указателей в этом отношении), у вас будет доступно 400 байт, но фрагментированные и 400 байтов непрерывной доступной памяти.Ваше выделение на шаге 2 не удастся из-за фрагментированной памяти.
Моя ошибка в использовании плохого примера.Таким образом, int *a = new int[100];
никогда не удаляется, и даже если он удаляется, в ответе говорится, что удален объект, а не указатель.Тем не менее указатели также имеют длину.
Когда у вас есть int *a = new int[100];
, у вас есть две части:
Память для a
(сам указатель) составляет 4 байта (при условии 32-битной архитектуры), выделенных в стеке.
Память, на которую указывает a
, составляет 400 байтов, выделенных в куче.
Память кучи будет освобождена при вызове delete[]a;
.Память стека (для самого указателя) будет освобождена в доступное пространство стека, когда * выходит из области видимости.
Вам нужно только позаботиться об удалении памяти кучи.Память стека освобождается / повторно используется по мере необходимости самой программой.