为什么没有内存泄漏? [英] Why no memory leak?

查看:152
本文介绍了为什么没有内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是旨在利用可变长度不变char和打印出来的用于记录一个不错的格式。我相信读者会对这可怎么改进建议,我表示欢迎。

令我百思不解的是,我希望这将是必要的free()的返回静态字符每次ToHexString()被调用。相反,我认为没有内存泄漏任何责任。即使寿我使用函数内联,因此不其返回值赋给一个变量。

我创建了一个简单的测试,在循环中调用此功能,用不同长度的CString和nMaxChars参数各一次。然后我看着VM的状态。内存分配为我的测试程序,并释放内存,从来没有改变过。

在我看来,它应该每一个malloc被调用时有所增加,没有免费的。

 静态字符* ToHexString(为const char *的CString,INT nMaxChars)
{
    静态字符* CSTR;    / *如果(80 GT;的strlen(CString的))
        nRawChars = strlen的(CString的);
    如果(nMaxChars> nRawChars)
        nRawChars = nMaxChars;
    * /
    如果(nMaxChars == 0)
        nMaxChars = 80;    的printf(有%i个字符\\ n,nMaxChars);    字符* cStr1;
    字符* cStr2;
    字符* cStr3;
    INT nLen = nMaxChars * 6;
    CSTR =释放calloc(nLen,sizeof的(炭));    cStr1 =释放calloc(10,sizeof的(炭));
    cStr2 =释放calloc(nLen,sizeof的(炭));
    cStr3 =释放calloc(nLen,sizeof的(炭));
    cStr1 [0] ='\\ 0';
    cStr2 [0] ='\\ 0';
    cStr3 [0] ='\\ 0';
    INT NC1 = 0;
    INT nRowCnt = 0;    对于(NC1 = 0;&NC1 LT; nMaxChars; NC1 ++)
    {
        ++ nRowCnt;
        如果(CString的[NC1] == 0×00)
            的snprintf(cStr1,8[00]);
        其他
            的snprintf(cStr1,8,[%02X],(无符号字符)的CString [NC1]);        如果((nRowCnt%8 == 0))
        {
            的snprintf(cStr3,nLen,%s%S \\ n,cStr2,cStr1);
        }
        其他
            的snprintf(cStr3,nLen,%s%S,cStr2,cStr1);        的snprintf(cStr2,nLen,%S,cStr3);
    }
    的snprintf(CSTR,nLen,%S,cStr3);
    免费(cStr1);
    免费(cStr2);
    免费(cStr3);
    返回(CSTR);
}

下面是调用程序:

 为(i = 0; I< 100;我++)
{
    memset的(安培; cBuff,0,255);
    的printf(读%S现在.. \\ n,CPORT);
    而(睡眠(1)== - 1);
    nChars =读(NPORT,cBuff,255);
    //的printf(读%我来自%s \\ n个字符,nChars,CPORT);
    如果(nChars&下; = 0)
        的printf(读来自%s \\ n 0个字符,CPORT);
    其他
        的printf(读%我来自%s \\ n%S \\ n个字符,nChars,CPORT,ToHexString(cBuff,nChars));
}


解决方案

以下是泄漏:

 静态无效memeat(无效)
{
        静态字符*富= NULL;        富=的malloc(1024);        返回;}

Valgrind的输出:

  == == 16167泄漏摘要:
== == 16167失去了肯定:4,096字节的4个块
== == 16167间接丧失:0字节0块
== == 16167失去了可能:0字节0块
== == 16167仍然可达:在1块1,024字节
== == 16167燮pressed:0字节0块
== == 16167与重新运行--leak检查=全看到内存泄露的细节

请注意,仍可达(1024字节)是被输入最后一次 memeat()的结果。静态指针仍持有到最后一个块的有效参考 memeat()程序退出时分配的。只是不previous块。

以下是的的泄漏:

 静态无效memeat(无效)
{
        静态字符*富= NULL;        富= realloc的(富,1024);        返回;}

Valgrind的输出:

  == == 16244泄漏摘要:
== == 16244失去了肯定:0字节0块
== == 16244间接丧失:0字节0块
== == 16244失去了可能:0字节0块
== == 16244仍然可达:在1块1,024字节
== == 16244燮pressed:0字节0块
== == 16244与重新运行--leak检查=全看到内存泄露的细节

在这里,地址指着已经释放,而现在指向新分配的地址,并将继续在未来的时间这样做 memeat()输入。

说明:

静态存储类型说,指针将指向相同的地址,每次初始化函数进入。不过,如果你的变更的每一个通过进入该功能时的malloc(地址)释放calloc(),你已经失去了参考从previous分配块。因此,泄漏,因为无论是否会返回一个新的地址。

依旧可达的valgrind中表示,所有分配的堆块仍然有一个有效的指针访问/操作/释放他们退出时。这是类似于分配内存的main(),而不是释放它,仅仅依靠操作系统上回收内存。

在简而言之,是的 - 你有一个泄漏。但是,可以比较容易地解决它。只是注意,您确实是靠你的操作系统上,除非你添加其他参数的函数,它只是告诉 ToHexString 拨打免费静态指针,你可以回收内存退出时使用。

与此类似:(全测试程序)

 的#include<&stdlib.h中GT;静态无效memeat(INT dofree)
{
        静态字符*富= NULL;        如果(dofree == 1安培;&安培;!富= NULL){
                免费(富);
                返回;
        }        富= realloc的(富,1024);        返回;}
INT主要(无效)
{
        无符号整型我;        对于(I = 0; I&小于5;我+ +)
                memeat(0);        memeat(1);
        返回0;
}

Valgrind的输出:

  == == 16285 HEAP摘要:
== == 16285在退出,使用:0块0字节
== == 16285总堆的使用情况:6 allocs,6的FreeS,6,144字节分配
== == 16285
== == 16285所有堆块被释放 - 无泄漏是可能的

在最终输出注意

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

此外,应该不会太难调整code,但我不明白为什么要使用静态存储开始。

The following is designed to take a variable length constant char and print it out in a nice format for logging. I am certain readers will have suggestions on how this can be improved, and I'd welcome it.

What puzzles me is that I expected it would be necessary to free() the returned static char each time ToHexString() is called. Instead, I see no memory leak whatsoever. Even tho I use the function inline and therefore do not assign its return value to a variable.

I created a simple test that calls this function in a loop, each time with a different length cString and nMaxChars parameter. Then I watched VM status. The memory allocation for my test program, and free memory, never changed.

It seems to me it should have increased each time a malloc is called and no free.

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);
}

Here is the calling routine:

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));
}

解决方案

The following is a leak:

static void memeat(void)
{
        static char *foo = NULL;

        foo = malloc(1024);

        return;

}

Valgrind output:

==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

Note, still reachable (1024 bytes) is the result of the last time memeat() was entered. The static pointer still held a valid reference to the last block memeat() allocated when the program exited. Just not the previous blocks.

The following is NOT a leak:

static void memeat(void)
{
        static char *foo = NULL;

        foo = realloc(foo, 1024);

        return;

}

Valgrind output:

==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

Here, the address foo pointed to has been freed, and foo now points to the newly allocated address, and will continue to do so the next time memeat() is entered.

Explanation:

The static storage type says that the pointer foo will point to the same address as initialized each time the function is entered. However, if you change that address each time the function is entered via malloc() or calloc(), you've lost the reference to the blocks from the previous allocation. Hence, a leak, since either is going to return a new address.

'Still Reachable' in valgrind means that that all allocated heap blocks still have a valid pointer to access / manipulate / free them upon exit. This is similar to allocating memory in main() and not freeing it, just relying on the OS to reclaim memory.

In short, yes - you have a leak. However, you can fix it rather easily. Just note that you are indeed relying on your OS to reclaim the memory unless you add another argument to your function that just tells ToHexString to call free on the static pointer, which you could use when exiting.

Similar to this: (full test program)

#include <stdlib.h>

static void memeat(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 output:

==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

Note on the final output:

Yes, 6144 bytes were actually allocated according to what malloc() returned while the program ran, but that just means the static pointer was freed, then reallocated according to the number of times memeat() was entered. The actual heap use of the program at any given time was actually just 2*1024, 1k to allocate the new pointer while the old one still existed waiting to be copied to the new one.

Again, it should not be too hard to adjust your code, but it isn't clear to me why you are using static storage to begin with.

这篇关于为什么没有内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆