以下内容旨在获取一个可变长度的常量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));
}
答案 0 :(得分:10)
以下是泄密:
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()
的有效引用。只是不是以前的块。
以下是 NOT 泄密:
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()
输入时继续执行此操作。< / p>
<强>解释强>
static
存储类型表示每次输入函数时,指针foo
将指向与初始化时相同的地址。但是,如果每次通过malloc()
或calloc()
输入功能时更改该地址,您就会丢失对先前分配的块的引用。因此,泄漏,因为要么将返回一个新地址。
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;
}
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用于分配新指针,而旧指针仍然存在,等待复制到新指针。
同样,调整代码应该不会太难,但我不清楚为什么要开始使用静态存储。
答案 1 :(得分:1)
这是内存泄漏。如果持续调用该函数,则程序使用的内存会增加。例如:
int main() {
while (1) {
ToHexString("testing the function", 20);
}
}
如果您运行此操作并使用系统监视工具观察该过程,您将看到已使用的内存不断增加。
程序中的泄漏可能并不明显,因为该函数每次调用只会泄漏几个字节,并且不会经常调用。因此,内存使用量的增加并不是很明显。
答案 2 :(得分:1)
我想在检查代码时指出两个让我头脑发热的东西:
cStr=calloc(nLen,sizeof(char));
为什么你没有对此进行错误检查....正如我从代码中看到的那样,对假设记忆零检查永远可用....危险.... 总是< / strong>从内存分配函数调用(例如calloc
,malloc
和realloc
)返回时检查 NULL 指针。 .it将始终成为程序员的责任,以管理指针的free
以使它们返回堆中。
另外,因为你将cStr
声明为char *
的静态指针,所以你根本没有释放它,事实上这条线证明了这一点:
printf("Read %i chars from %s\n%s\n",nChars,cPort,ToHexString(cBuff,nChars)); ^^^^^^^^^^^
你最好这样做:
char *hexedString; hexedString = ToHexString(cBuff, nChars); .... printf("Read %i chars from %s\n%s\n",nChars,cPort,hexedString); .... free(hexedString);
答案 3 :(得分:0)
您可以在新数组中返回例程的结果。使用您的模型,使用结果释放此数组的责任在于调用者。所以,在调用者中,你应该将你的例程的结果存储在一个临时的,用它做你想做的任何事情,然后在最后释放()它。