我对malloc行为有疑问。 有2个c文件
myTools.c和mainFile.c
mainFile.c is =>
int main(){
int i=1;
char *request="blablabla"//vary in situation.Not static
while(i==1)//forever Loop
{
...
strcpy(response,getFile(request));
...
}
}
myTools.c是==>
.
.//something else
.
char *getFile(char *request)
{
char *retVal;
...//some tcp request
retVal=malloc(strlen(buffer));
strcpy(retVal,buffer);
..//some char array operations
return retVal;
}
.
.//something else
.
我找不到释放retVal的方法,或者我想知道我需要释放retVal吗?
它可以在m68k嵌入式平台上运行uClinux,因此内存有限。
它可能会导致任何记忆问题或任何记忆饥饿吗?
或影响程序的运行时行为?
答案 0 :(得分:4)
每次调用getFile()时都会泄漏内存。
一种解决方案是:
while(i==1)//forever Loop
{
...
char* temp = getFile( request );
strcpy(response,temp);
free( temp );
...
}
答案 1 :(得分:2)
由于你从getFile()
返回一个指针,或许你可以简单地将它分配给main()
中的指针变量,绕过strcpy()
的双重使用?然后,您可以free()
main()
中的{{1}}内存。{/ 1>
我不确定,但不明白为什么那样不起作用。
答案 2 :(得分:1)
strcpy(response,getFile(request))
可能会导致程序崩溃,因为response
指向只读内存。
答案 3 :(得分:1)
strcpy(response,getFile(request));
应分为:
char *tmp = getFile(request);
strcpy(response, tmp );
free( tmp );
有时将其称为strdup()样式分配,不推荐使用。 您应该在调用代码中分配缓冲区,如:
char *buf2 = malloc(strlen(buffer));
并致电
getFile( buf2, strlen( buffer ), input );
// use buf2
free( buf2 );
答案 4 :(得分:1)
在嵌入式系统中,malloc()通常用于在启动时分配内存,该内存将在系统运行时使用,并且永远不会自由()d。
但是你不应该定期做这样的事情,因为如果你不再释放()它会耗尽你的记忆。
您在示例中所做的是在while循环中每轮泄漏一个缓冲区。
你应该做的是,在你的循环中调用free(),但要注意这仍然会破坏menmory,这在长时间运行的嵌入式系统中尤其糟糕。
如果您事先知道需要多少内存:在循环外部将缓冲区malloc并在循环中重用:
response = malloc(MAX_BUF_SIZE);
while (1) {
get_file(response, MAX_BUF_SIZE); /* always good to pass the buf size and check */ ... use response ...
}
或者,如果您事先不知道尺寸,可以是:
response = NULL;
size = 0;
while (1) {
get_file(&response, &size);
... use response ...
}
void get_file(char **buf, int *s)
{
size = ... somehow determine the needed size ...
if (size > *s)
*buf = realloc(*buf, size); /* only does free/malloc internaly if it has to no room */
strncpy(*buf, whatver, size);
}
您应该始终使用strncpy
而永远不要strcpy
!
在您的示例中使用strcpy令人困惑,无法看到响应获取其内存的位置,是静态分配的吗?之前是否曾被拍过来?
如果响应已指向vaid缓冲区,则应将指针传递到缓冲区getFile()
并直接复制buffer
。
如果响应未指向有效的内存缓冲区,则无论如何都无法正常工作。
答案 5 :(得分:1)
每当您为某些功能创建接口时,您需要考虑资源管理 - 各种对象的生命周期以及这些对象的生命周期是如何管理的。对于像C和C ++这样没有实现垃圾收集的语言尤其如此,但即使在垃圾收集语言中,也需要考虑到这一点(对于非内存资源并且可能确保不保留对象引用)无限期)。
无论如何,对于C,API可以通过多种方式处理“输出”对象。一些更常见的模式是:
对于选项1,调用者提供一个缓冲区,通过传递指针来放置结果。对于可变长度数据,如字符串,接口也允许调用者传递输出缓冲区的大小,这样函数可以避免在缓冲区外写入,这一点很重要。对于getFile()
函数,原型可能如下所示:
int getFile(char const* request, char* result, int result_size);
调用者传入一个指针来放置结果和传入缓冲区的大小。该函数可能会在失败时返回负数(例如网络故障),并在成功时返回结果的大小。如果成功返回的大小大于提供的缓冲区,则调用者知道完整结果未放入缓冲区(因为它不够大)。如果你走这条路线,重要的是要考虑'\ 0'终结符字符并清楚地表明它是否包含在返回值中,以及如果结果太大(我推荐),缓冲区是否终止。此外,请确保如果传入零大小的缓冲区,则无论是否传入非NULL指针,函数都不会向缓冲区写入任何内容(这是使函数返回所需大小的常用模式)在这种情况下缓冲区。)
对于选项2,该函数将分配一个适当的缓冲区并将指针返回给调用者。在这种情况下,调用者需要有一种方法可以在缓冲区完成后释放缓冲区以避免内存泄漏。一种方法是记录调用者需要对函数返回的指针调用free()
(暗示函数将使用malloc()
或calloc()
分配指针。另一个是让使用该函数的接口还包括一个释放例程,也许getFile_free()
(如果我要走这条路线,我肯定会重新考虑这些函数的命名)。这使得该API的实现可以自由地分配它返回的缓冲区但是它认为合适 - 它不限于使用malloc()
/ free()
(虽然它可以)。
对于嵌入式系统(特别是小型系统 - 可能不是基于Linux的系统),我认为人们可能会选择选项1.这使得API的用户可以自由地完全避免动态内存分配,这对于嵌入式系统不使用动态内存。此外,使用动态内存分配的系统仍然可以使用选项1的模式 - 它只需要更多的工作,但是这项工作可以包含在看起来与选项2完全相同的东西中,所以你可以吃蛋糕并吃掉它。
答案 6 :(得分:0)
是的,它最终会导致内存不足,这将导致程序崩溃。
一个有助于解决此类问题的简单规则是始终记住释放内存 如果可能的话,与分配的范围相同。
在你的情况下,在返回调用之后显然不可能释放它,因此在父范围内实际分配它是有意义的,即。在main
函数中,将分配的指针作为第二个参数传递给getFile函数,并直接写入它,假设您确保它足够大以包含所有字符。
答案 7 :(得分:0)
首先,* retVal放在 getFile函数,因此范围 * retVal仅限于该特定功能及其使用的存储空间 将自动设置为FREE一次 该函数终止/返回。
变量的范围决定了它的生命周期/可用性,一旦生命周期结束并且你没有释放数据保留在那里的块,它可以通过指针访问,但是内存块是一种MARKED AS FREE并且在没有任何麻烦的情况下被覆盖。
其次,尼克非常正确,你 每次getFile()都会浪费内存 被称为,因为它在主要功能 并且在程序运行之前有范围。
希望这会有所帮助,如果不是,我会很高兴帮助我告诉我们。)