为什么没有内存泄漏?

以下内容旨在获取一个可变长度的常量char,并以一种很好的格式打印出来以进行日志记录。 我相信读者会对如何改进这方面提出建议,我对此表示欢迎。

令我困惑的是,我希望每次调用ToHexString()时都需要free()返回的静态char。 相反,我认为没有任何内存泄漏。 即使我使用内联函数,因此也不会将其返回值赋给变量。

我创建了一个简单的测试,在循环中调用此函数,每次使用不同长度的cString和nMaxChars参数。 然后我看了VM的状态。 我的测试程序和可用内存的内存分配从未改变。

在我看来,每次调用malloc并且没有空闲时它应该增加。

static char *ToHexString(const char *cString,int nMaxChars) { static char *cStr; /*if (80>strlen(cString)) nRawChars=strlen(cString); if (nMaxChars>nRawChars) nRawChars=nMaxChars; */ if (nMaxChars==0) nMaxChars=80; printf("There are %i chars\n",nMaxChars); char *cStr1; char *cStr2; char *cStr3; int nLen=nMaxChars*6; cStr=calloc(nLen,sizeof(char)); cStr1=calloc(10,sizeof(char)); cStr2=calloc(nLen,sizeof(char)); cStr3=calloc(nLen,sizeof(char)); cStr1[0]='\0'; cStr2[0]='\0'; cStr3[0]='\0'; int nC1=0; int nRowCnt=0; for (nC1=0;nC1<nMaxChars;nC1++) { ++nRowCnt; if (cString[nC1]==0x00) snprintf(cStr1,8,"[00] "); else snprintf(cStr1,8,"[%02x] ",(unsigned char)cString[nC1]); if ( (nRowCnt%8==0) ) { snprintf(cStr3,nLen,"%s%s\n",cStr2,cStr1); } else snprintf(cStr3,nLen,"%s%s",cStr2,cStr1); snprintf(cStr2,nLen,"%s",cStr3); } snprintf(cStr,nLen,"%s",cStr3); free(cStr1); free(cStr2); free(cStr3); return(cStr); } 

这是调用例程:

 for (i=0;i<100;i++) { memset(&cBuff, 0,255); printf("Reading %s now..\n",cPort); while (sleep(1)==-1); nChars=read(nPort, cBuff, 255); //printf("Read %i chars from %s\n",nChars,cPort); if (nChars<=0) printf("Read 0 chars from %s\n",cPort); else printf("Read %i chars from %s\n%s\n",nChars,cPort,ToHexString(cBuff,nChars)); } 

以下是泄漏:

 static void memeat(void) { static char *foo = NULL; foo = malloc(1024); return; } 

Valgrind输出:

 ==16167== LEAK SUMMARY: ==16167== definitely lost: 4,096 bytes in 4 blocks ==16167== indirectly lost: 0 bytes in 0 blocks ==16167== possibly lost: 0 bytes in 0 blocks ==16167== still reachable: 1,024 bytes in 1 blocks ==16167== suppressed: 0 bytes in 0 blocks ==16167== Rerun with --leak-check=full to see details of leaked memory 

注意, still reachable (1024字节)是上次输入memeat()结果。 静态指针仍保持对程序退出时分配的最后一个块memeat()的有效引用。 只是不是以前的块。

以下不是泄漏:

 static void memeat(void) { static char *foo = NULL; foo = realloc(foo, 1024); return; } 

Valgrind输出:

 ==16244== LEAK SUMMARY: ==16244== definitely lost: 0 bytes in 0 blocks ==16244== indirectly lost: 0 bytes in 0 blocks ==16244== possibly lost: 0 bytes in 0 blocks ==16244== still reachable: 1,024 bytes in 1 blocks ==16244== suppressed: 0 bytes in 0 blocks ==16244== Rerun with --leak-check=full to see details of leaked memory 

这里,指向的地址foo已被释放, foo现在指向新分配的地址,并且在下次输入memeat()时将继续这样做。

说明:

static存储类型表示每次输入函数时指针foo将指向与初始化时相同的地址。 但是,如果每次通过malloc()calloc()输入函数时更改该地址,则会丢失对先前分配的块的引用。 因此,泄漏,因为要么将返回一个新地址。

valgrind中的“仍然可访问”意味着所有已分配的堆块仍然具有在退出时访问/操作/释放它们的有效指针。 这类似于在main()分配内存而不释放内存,只是依靠操作系统来回收内存。

简而言之,是的 – 你有泄漏。 但是,您可以轻松地修复它。 请注意,你确实依赖你的操作系统来回收内存,除非你向你的函数添加另一个参数,它告诉ToHexString在静态指针上调用free,你可以在退出时使用它。

与此类似:(完整的测试程序)

 #include  static void memeat(unsigned int dofree) { static char *foo = NULL; if (dofree == 1 && foo != NULL) { free(foo); return; } foo = realloc(foo, 1024); return; } int main(void) { unsigned int i; for (i = 0; i < 5; i ++) memeat(0); memeat(1); return 0; } 

Valgrind输出:

 ==16285== HEAP SUMMARY: ==16285== in use at exit: 0 bytes in 0 blocks ==16285== total heap usage: 6 allocs, 6 frees, 6,144 bytes allocated ==16285== ==16285== All heap blocks were freed -- no leaks are possible 

关于最终输出的注意事项

是的,根据malloc()在程序运行时返回的内容实际分配了6144个字节,但这只是意味着释放了静态指针,然后根据输入memeat()的次数重新分配。 程序在任何给定时间的实际堆使用实际上只有2 * 1024,1k用于分配新指针,而旧指针仍然存在等待复制到新指针。

同样,调整代码应该不会太难,但我不清楚为什么你开始使用静态存储。

这是一个内存泄漏。 如果持续调用该函数,程序使用的内存会增加。 例如:

 int main() { while (1) { ToHexString("testing the function", 20); } } 

如果您运行此操作并使用系统监视工具观察该过程,您将看到已使用的内存不断增加。

泄漏在您的程序中可能并不明显,因为该函数每次调用只泄漏几个字节,并且不经常调用。 因此,内存使用量的增加并不是很明显。

在检查代码时,我想指出两个让我头脑发热的东西:

 CSTR =释放calloc(nLen,的sizeof(char)的);

为什么你没有对此进行错误检查….正如我从代码中看到的那样,对假设存储器始终可用的零检查….危险…. 始终检查返回时的NULL指针一个内存分配函数调用,如callocmallocrealloc ……它总是成为程序员的责任,可以管理free指针以将它们返回堆中。

另外,因为你已经将cStr声明为char *的静态指针,所以你根本没有释放它,事实上这条线certificate了这一点:

 printf(“读取%s字符来自%s \ n%s \ n”,nChars,cPort,ToHexString(cBuff,nChars));
                                                   ^^^^^^^^^^^

你最好这样做:

 char * hexedString;
 hexedString = ToHexString(cBuff,nChars);
 ....
 printf(“读取%s字符来自%s \ n%s \ n”,nChars,cPort,hexedString);
 ....
自由(hexedString);

您可以在新数组中返回例程的结果。 使用您的模型,使用结果释放此数组的责任在于调用者。 因此,在调用者中,您应该将例程的结果存储在临时文件中,随意执行任何操作,然后在结束时释放()它。