在 C 和 C++ 中,释放 NULL 指针将导致什么都不做。
尽管如此,我还是看到人们说如果您“释放内存两次”,可能会发生内存损坏。
这是真的?当您两次释放内存时,幕后发生了什么?
在 C 和 C++ 中,释放 NULL 指针将导致什么都不做。
尽管如此,我还是看到人们说如果您“释放内存两次”,可能会发生内存损坏。
这是真的?当您两次释放内存时,幕后发生了什么?
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
第一次 ing 之后,你应该这样做p = NULL
,所以如果(有机会)free(p)
再次调用,什么都不会发生。
这就是为什么两次释放内存是未定义的:Why free crashing when called enough
释放内存不会将指针设置为空。指针仍然指向它曾经拥有的内存,但现在已将所有权转移回堆管理器。
堆管理器可能已经重新分配了你的过时指针指向的内存。
再次释放它与说 不一样free(NULL)
,并且会导致未定义的行为。
这是未定义的行为,可能导致堆损坏或其他严重后果。
free()
对于空指针,只需检查内部的指针值并返回。该检查无助于两次释放块。
这就是通常发生的事情。堆实现获取地址并尝试通过修改自己的服务数据来“获取”该地址处的块的所有权。根据堆的实现,任何事情都可能发生。也许它可以工作并且没有任何反应,也许服务数据已损坏并且您遇到了堆损坏。
所以不要这样做。这是未定义的行为。任何不好的事情都可能发生。
是的,几乎总是导致崩溃的“未定义行为”。(虽然“未定义的行为”定义为“任何事情”,但各种类型的错误通常以完全可预测的方式表现。在 free() 的情况下,行为总是段错误或操作系统各自的“内存保护错误”特征。)
如果您 free() 指向除 NULL 或您 malloc'd 之外的任何其他内容的指针,则相同。
char x; char* p=&x; free(p);
// 碰撞。
为了避免释放两次,我总是使用 MACRO 来释放内存:
#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p ) \
if( _p ) \
{ \
free( _p ); \
_p = NULL; \
}
此宏设置 p = NULL 以避免悬空指针。
当您在指针上调用 free 时,您的指针不会被设置为 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
你可以看到,free 没有对指针做任何事情,只是告诉系统内存可以重用。
free() 释放 ptr 指向的内存空间,该内存空间必须由先前对 malloc()、calloc() 或 realloc() 的调用返回。否则,或者如果之前已经调用过 free(ptr),则会发生未定义的行为。如果 ptr 为 NULL,则不执行任何操作。
因此,您会得到未定义的行为,并且任何事情都可能发生。
1) 动态内存的处理不是由编译器完成的。有运行时库可以解决这个问题。例如。: glibc 提供了 malloc 和 free 等 API,它们在内部进行系统调用 (sys_brk) 来处理堆区域。
2) 两次释放相同的内存是指这样的情况:假设你有 char *cptr;
您使用以下方法分配内存: cptr = (char *) malloc (SIZE);
现在,当您不再需要此内存时,可以使用以下命令释放它:free(cptr);
现在这里发生的是 cptr 指向的内存可以免费使用。
假设在程序的稍后时间点您再次调用 free(cptr),那么这不是一个有效条件。这种两次释放相同内存的情况称为“两次释放内存”问题。
多次释放内存可能会产生不良后果。您可以运行这段代码来查看您的计算机可能发生的情况。
#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 的情况