为什么没有内存泄漏?

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用于分配新指针,而旧指针仍然存在等待复制到新指针.

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