Не правильно ли удалены указатели фрагмента памяти? - PullRequest
2 голосов
/ 11 июня 2010

Это в основном вопрос. Если у меня есть указатель int *a = &someIntVar, и я не удаляю его по ходу программы, он остается в памяти после завершения программы? Это случай фрагментации данных?

EDIT:

Моя ошибка в использовании плохого примера. Таким образом, int *a = new int[100]; никогда не удаляется, и даже если он удаляется, в ответе говорится, что удален объект, а не указатель. Все же указатели также имеют длину. Таким образом, вопрос заключается в том, в ОС Windows или Linux, он автоматически очищается после указателей? (Предположим, C ++)

Ответы [ 6 ]

4 голосов
/ 11 июня 2010

Нет, вся память, выделенная процессом, обычно освобождается при завершении процесса. Но это может не относиться к таким вещам, как файловые дескрипторы или графические ресурсы (т.е. в дескрипторах контекста устройства Win32, растровых изображениях и т.

4 голосов
/ 11 июня 2010

Так как вы не new редактировали этот указатель, у вас нет утечки памяти.

Если бы вы сделали int* a = new int;, а не delete a, то вы бы пропустили a.

Как правило, число new с должно равняться числу delete с.

Когда someIntVar выходит из области видимости, стек разворачивается, и его память освобождается, а a, конечно же, остается висящим.

1 голос
/ 11 июня 2010

После int *a = new int[100]; вы используете sizeof(a) + sizeof(int[100]) байтов памяти.После delete a вы все еще используете sizeof(a) байтов памяти.Это логично: вы можете написать a = new int[50]; далее.Память a освобождается только тогда, когда сама a выходит из области видимости.Если a является глобальным, это будет при завершении программы.

1 голос
/ 11 июня 2010

Не правильно ли удалены фрагменты памяти указателей?

Нет. Множество выделений и выпусков памяти будут фрагментировать память.

Вот интуитивнообъяснение распределения памяти (оно более сложное, и мой пример в лучшем случае наивен и игнорирует множество проблем, но должно дать вам некоторое представление).

Распределение памяти обычно происходит в (по крайней мере) двухшаги:

  1. ОС выделяет блоки памяти для приложения.

  2. Приложение выделяет память из доступных блоков для собственного использования.

Если приложение использует всю доступную память (или больше не может выделять), ОС выделит приложению больше памяти.Это делается прозрачно для приложения, но требует времени (поэтому выделение памяти происходит медленно).

Когда приложение освобождает память, адреса / блоки помечаются как свободные и будут повторно использоваться в последующих запросах выделения (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;.Память стека (для самого указателя) будет освобождена в доступное пространство стека, когда * выходит из области видимости.

Вам нужно только позаботиться об удалении памяти кучи.Память стека освобождается / повторно используется по мере необходимости самой программой.

1 голос
/ 11 июня 2010

Один запутанный факт о delete p заключается в том, что он на самом деле не удаляет p, а *p. То есть вы не удаляете указатель, а указатель. Всякий раз, когда вы видите delete, вы должны думать об этом как delete_what_is_pointed_to_by. Ах да, и только delete что вы new.

0 голосов
/ 11 июня 2010

Попробуйте это на любой ОС, которую вы используете:

  1. Начните с наблюдения за объемом памяти процесса.Используйте top в Linux и диспетчер задач в Windows.
  2. Выделите память на 100000 как в int * p = new int [100000];
  3. Обратите внимание на объем памяти процесса.Это должно увеличиться по крайней мере на 100k * 4 байта.Теперь посмотрите на «свободную» память, оставленную для использования другими процессами.
  4. Пусть программа работает, не удаляйте ничего.После выполнения пространство возвращается в систему - вы должны увидеть, что доступная память для использования в других программах теперь увеличивается.

В качестве примечания, не думайте, что если вы удалите []п;в середине кода ваши 100k * 4 немедленно возвращаются в систему.Это может или не может быть правдой - Linux, например, имеет свой собственный менеджер памяти, который принимает такие решения.

Арпан

...