如果您不使用malloc'ed块会发生什么?

时间:2009-04-10 20:58:46

标签: c memory-leaks free malloc

考虑以下C代码:

int main(){  
    int* c;  
    c = (int*)malloc(sizeof(int));  
    c = 0xdeadbeef;  
    free(c);  
    return 0;  
}

这将是段错误,因为你试图释放c,这不是之前已经过malloc的东西。我的问题是我刚刚使用malloc'ed的块会发生什么?显然c不再指向它了,所以它不能被使用,但是它仍然被认为是“免费”列表的一部分,还是这是一个明确的内存泄漏?

7 个答案:

答案 0 :(得分:12)

这是一个泄漏。当程序终止时,操作系统将回收它。

答案 1 :(得分:10)

仍然分配了内存,导致内存泄漏。你想要其他任何方式吗?机器/编译器确实没有办法知道应该回收你分配的内存。如果这不是正确的行为,那么您的代码将以概率方式运行:您永远不会真正信任该代码。

您可以在将来的某个时间点重新指向该内存块,因此自动释放它会从您的下方拉出地毯。

答案 2 :(得分:1)

假设您将c = 7;更改为*c = 7;

,该代码不会出现段错误

答案 3 :(得分:1)

在malloc()之后,c是一个包含内存地址的变量。在这种情况下,c具有您分配的第一个字节的内存地址的值。

当您说c = 7时,您说“c现在指向内存地址'7'”。因为,在这种情况下,内存地址“7”没有分配给您的进程,您不能free()它。从理论上讲,内存地址“7”(或0xa73c930bf,或者你设置的任何内容)确实可以分配给你的进程,在这种情况下free()会成功。

但是,更改c的值后,仍会分配内存。你的进程仍然有内存及其数据 - 你刚丢失了指针。你不知道那个记忆的起源。

这是一个好的情况。在C中,您可能有不同的变量指向该内存地址。您甚至可能有一个“int”,而不是存储该内存地址的“int *”。 C不会试图跟踪你是否存储了特定的内存地址 - 这实际上只是一个数字。这样做将是一项不可能完成的任务,因为任何追踪的尝试都需要失去C指针提供的一些灵活性。

所以回答你的问题:由于你无法跟踪c的值,这个程序有内存泄漏。而且,我的意思是你的内存不能被你的程序使用,因而浪费了资源。

但是,当程序退出时,所有已分配给您的进程的内存都将被释放,并可供其他程序使用。

答案 4 :(得分:1)

请不要激怒我,但我不清楚你的问题是什么。显然,你所做的是与语言打算让你做的事情直接冲突。这相当于说“如果我用汽车的油箱装满灭火器液体会发生什么,只是因为灭火器的喷嘴恰好装在油箱孔里”。 我不是想成为一个混蛋,我只是不清楚为什么这个特殊的问题?我可以想到无数的问题,利用指针的力量,并想知道有多少方法错误地使用它们,导致应用程序失败。 你有没有想要实现的东西,你的代码*会做什么,只要你能找到正确的方法去做?或者您是否想知道是否有一些内部机制可以跟踪您的指针并帮助您在意外丢失记录时回收该内存? (如果是的话,上面已回答了这个问题)。

答案 5 :(得分:1)

嗯,imo,你现在得到的段错误并不是因为你试图释放以前没有分配的内存,因为你试图引用操作系统未授予你权限的内存地址而发生段错误给你(这是分段错误的定义)。

有些实验,比如说你会在valgrind中运行你的示例代码,你会得到它作为输出:

    ==6945== Invalid free() / delete / delete[]
    ==6945==    at 0x402265C: free (vg_replace_malloc.c:323)
    ==6945==    by 0x80483D5: main (bla.c:6)
    ==6945==  Address 0x7 is not stack'd, malloc'd or (recently) free'd
    ==6945== 
    ==6945== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 1)
    ==6945== malloc/free: in use at exit: 4 bytes in 1 blocks.
    ==6945== malloc/free: 1 allocs, 1 frees, 4 bytes allocated.

所以这是一个内存泄漏'pur sang'。现在假设您将更改代码,以便您尝试释放的指针“接近”您分配的指针(因此操作系统仍然知道您可以访问它,操作系统不会在字节边界上授予内存访问权限)。假设我们修改代码如下:

int main(){  
    int* c;  
    c = (int*)malloc(sizeof(int));  
    c++;
    free(c);  
    return 0;  
}

运行此应用程序时,您不会再遇到分段错误(由内核发出),而是来自glibc的警告(malloc()和free()的所有者)

    edb@Flying-Spaghetti-Monster:/tmp$ ./a.out 
    *** glibc detected *** ./a.out: free(): invalid pointer: 0x0804a00c ***
    ... followed by a trace

所以你试图释放一些内核知道它属于你的内存,但是哪个glibc不记得把它交给你了。如果你在valgrind中运行它(通过在libc中替换free(),malloc(),realloc(),...函数并自行执行记帐来运行),你将得到这个输出:

    ==6955== Invalid free() / delete / delete[]
    ==6955==    at 0x402265C: free (vg_replace_malloc.c:323)
    ==6955==    by 0x80483D2: main (bla.c:5)
    ==6955==  Address 0x418a02c is 0 bytes after a block of size 4 alloc'd
    ==6955==    at 0x4022AB8: malloc (vg_replace_malloc.c:207)
    ==6955==    by 0x80483C0: main (bla.c:3)
    ==6955== 
    ==6955== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 1)
    ==6955== malloc/free: in use at exit: 4 bytes in 1 blocks.
    ==6955== malloc/free: 1 allocs, 1 frees, 4 bytes allocated.

答案 6 :(得分:0)

请注意,malloc()返回的值不需要投放,因为转化void* - > int*是自动的。

你也可以像这样重写这个电话:

c = malloc(sizeof *c);

现在,如果您更改c的类型,则根本不必重写分配。

[编辑]

检查分配是否成功(即c != NULL)也是一个好主意。