Mar*_*rds 4 c malloc free memory-leaks
以下内容旨在获取一个可变长度的常量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);
}
Run Code Online (Sandbox Code Playgroud)
这是调用例程:
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));
}
Run Code Online (Sandbox Code Playgroud)
Tim*_*ost 10
以下是泄漏:
static void memeat(void)
{
static char *foo = NULL;
foo = malloc(1024);
return;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
注意,still reachable(1024字节)是最后一次memeat()输入的结果.静态指针仍然保持memeat()对程序退出时分配的最后一个块的有效引用.只是不是以前的块.
以下不是泄漏:
static void memeat(void)
{
static char *foo = NULL;
foo = realloc(foo, 1024);
return;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这里,foo指向的地址已被释放,foo现在指向新分配的地址,并在下次memeat()输入时继续这样做.
说明:
该static存储类型说,指针foo将指向相同的地址每次进入函数时初始化.但是,如果每次通过或输入函数时更改该地址,则您将丢失对先前分配的块的引用.因此,泄漏,因为要么返回一个新的地址.malloc()calloc()
valgrind中的"仍然可访问"意味着所有已分配的堆块仍然具有在退出时访问/操纵/释放它们的有效指针.这类似于分配内存main()而不是释放内存,只需依靠操作系统来回收内存.
简而言之,是的 - 你有泄漏.但是,您可以轻松地修复它.请注意,你确实依赖你的操作系统来回收内存,除非你为你的函数添加另一个参数,它告诉你ToHexString在静态指针上调用free,你可以在退出时使用它.
与此类似:(完整的测试程序)
#include <stdlib.h>
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;
}
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
关于最终输出的注意事项:
是的,根据malloc()程序运行时返回的内容实际分配了6144个字节,但这只是意味着释放了静态指针,然后根据memeat()输入的次数重新分配.在任何给定时间,程序的实际堆使用实际上只有2*1024,1k用于分配新指针,而旧指针仍然存在等待复制到新指针.
同样,调整代码应该不会太难,但我不清楚为什么你开始使用静态存储.