Освобождение памяти дважды
В C и С++ освобождение указателя NULL не приведет к тому, что ничего не сделано.
Тем не менее, я вижу, что люди говорят, что повреждение памяти может произойти, если вы "освобождаете память дважды".
Это правда? Что происходит под капотом, когда вы освобождаете память дважды?
Ответы
Ответ 1
int *p = malloc(sizeof(int));
//value of p is now lets say 0x12345678
*p = 2;
free(p); //memory pointer is freed, but still value of p is 0x12345678
//now, if you free again, you get a crash or undefined behavior.
Итак, после free
в первый раз вы должны сделать p = NULL
, поэтому, если (случайно), free(p)
вызывается снова, ничего не произойдет.
Вот почему освобождение памяти в два раза меньше undefined: Почему бесплатные сбои при вызове дважды
Ответ 2
Свободная память не устанавливает указатель на нуль. Указатель по-прежнему указывает на память, к которой он принадлежал, но который теперь получил право собственности, переданному менеджеру кучи.
Менеджер кучи может с тех пор перераспределить память, на которую указывает ваш устаревший указатель.
Освобождение снова - это не то же самое, что сказать free(NULL)
, и приведет к поведению undefined.
Ответ 3
Это поведение undefined, которое может привести к повреждению кучи или другим серьезным последствиям.
free()
для нулевого указателя просто проверяет значение указателя внутри и возвращает. Эта проверка не поможет избавиться от блока дважды.
Вот что обычно происходит. Реализация кучи получает адрес и пытается "взять на себя ответственность" блока по этому адресу, изменив свои собственные служебные данные. В зависимости от реализации кучи все может случиться. Возможно, это работает, и ничего не происходит, возможно, данные службы повреждены, и у вас есть повреждение кучи.
Так что не делай этого. Это поведение undefined. Что бы ни случилось, может случиться.
Ответ 4
Да, "undefined поведение", которое почти всегда приводит к сбою.
(в то время как "undefined поведение" по определению означает "что угодно", различные типы ошибок часто ведут себя вполне предсказуемым образом. В случае free() поведение неизменно является segfault или соответствующей "ошибкой защиты памяти", характерной для ОС. )
То же самое, если вы освободите() указатель на что-либо еще, кроме NULL или что-то, что вы malloc'd.
char x; char* p=&x; free(p);
//сбой.
Ответ 5
Чтобы избежать бесплатного дважды, я всегда использую MACRO для свободной памяти:
#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p ) \
if( _p ) \
{ \
free( _p ); \
_p = NULL; \
}
этот макрос устанавливает p = NULL, чтобы избежать оборванного указателя.
Ответ 6
Когда вы вызываете бесплатный указатель, ваш указатель не будет установлен в NULL. Свободное пространство возвращается только в пул, который будет доступен для распределения снова. Вот пример тестирования:
#include <stdio.h>
#include <stdlib.h>
int main(){
int* ptr = (int*)malloc(sizeof(int));
printf("Address before free: %p\n", ptr);
free(ptr);
printf("Address after free: %p\n", ptr);
return 0;
}
Эта программа выводит для меня:
Address before free: 0x950a008
Address after free: 0x950a008
и вы можете видеть, что бесплатный ничего не сделал с указателем, но только сообщил системе, что память доступна для повторного использования.
Ответ 7
free() освобождает пространство памяти к ptr, который, должно быть, был возвращенный предыдущим вызовом malloc(), calloc() или realloc(). В противном случае, или если free (ptr) уже вызывается раньше, undefinedпроисходит поведение. Если ptr имеет значение NULL, операция не выполняется.
Итак, вы получаете поведение undefined, и все может случиться.
Ответ 8
1) Обработка динамической памяти не выполняется компилятором. Есть библиотеки времени выполнения, которые позаботятся об этом. Напр.: glibc предоставляет API, такие как malloc и free, которые внутренне выполняют системные вызовы (sys_brk) для обработки области кучи.
2) Освобождение одной и той же памяти в два раза относится к следующим условиям:
Предположим, что у вас есть char * cptr;
Вы выделяете память, используя:
cptr = (char *) malloc (SIZE);
Теперь, когда вам больше не нужна эта память, вы можете освободить ее, используя следующую команду:
свободные (СРКИ);
Теперь здесь происходит то, что память, на которую указывает cptr, бесплатна для использования.
Предположим, что в более поздний момент в программе вы снова вызываете бесплатный (cptr), то это не является допустимым условием. Этот сценарий, в котором вы освобождаете одну и ту же память дважды, известен как проблема "освобождение памяти дважды".
Ответ 9
Освобождение памяти более одного раза может иметь плохие последствия. Вы можете запустить этот фрагмент кода, чтобы узнать, что может случиться для вашего компьютера.
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* malloc, free, rand */
int main ()
{
int i,n;
char * buffer;
printf ("How long do you want the string? ");
scanf ("%d", &i);
buffer = (char*) malloc (i+1);
if (buffer==NULL) exit (1);
for (n=0; n<i; n++)
buffer[n]=rand()%26+'a';
buffer[i]='\0';
printf ("Random string: %s\n",buffer);
free (buffer);
free (buffer);
return 0;
}
Многие стандартные библиотеки, такие как CSparse, используют функцию-оболочку, которая обрабатывает проблемы с памятью. Я скопировал здесь функцию:
/* wrapper for free */
void *cs_free (void *p)
{
if (p) free (p) ; /* free p if it is not already NULL */
return (NULL) ; /* return NULL to simplify the use of
}
Эта функция может обрабатывать проблемы с памятью. Обратите внимание, что вам необходимо позаботиться о том, что malloc возвращает NULL в некоторых случаях