【问题标题】:How to recycle and reuse allocated memory?如何回收和重用分配的内存?
【发布时间】:2015-02-07 23:46:46
【问题描述】:

我现在正在研究的是一个基于状态的解析器,用于处理来自流的任何输入。我的教授告诉我这是避免特殊情况的最好方法。我设置它的方式是使用函数,我在尝试重用分配的内存时遇到了一些麻烦,所以我不会造成任何泄漏。我正在解析的是多个参数。每个参数都有一个名称和一个值。一个示例输入是:

parameterName = 500;

名称为parameterName,类型为integer,值为500

我能够成功地解析其中一个而没有内存泄漏。但是,执行第二个参数会导致泄漏,我知道原因:这是 malloc 在我的参数名称上的多次使用。

看一下解析代码:

int main()
{
    int x;
    char c;
    char *nameTemp;
    int hasName = 0;
    int hasEqual = 0;

    /* ParameterManager values */
    ParameterManager *pm;
    pm = PM_create(500);
    if((PM_manage(pm, "name", INT_TYPE, 1)));

    while((x = getchar()) != EOF)
    {
        /* Cast int to char */
        c = (char)x;

        /* Whitespace state */
        if((isspace(c)))
        {
            c = whitespace();
        }

        /* Comment state */
        if(c == '#')
        {
            c = comment();          
        }

        /* Name state */    
        if(((isalnum(c)) && hasEqual == 0 && hasName == 0))
        {
            nameTemp = name(c);
            printf("Name: %s\n", nameTemp);
            hasName = 1;
        }

        /* Equal state */
        if(c == '=' && hasName == 1 && hasEqual == 0)
        {
            hasEqual = 1;
        }

        /* Value state */
        if((isalnum(c)) && hasName == 1 && hasEqual == 1)
        {
            getValues(c, nameTemp, pm->t_List, pm->m_List);
            hasName = 0;
            hasEqual = 0;
        }
    }

    free(nameTemp);
    if((PM_destroy(pm)) && DEBUG) printf("Success destroying PM.\n");
    return 0;
}

nameTemp = name(c) 下的/* Name state */ 行返回一个分配的字符串。该字符串稍后被传递以执行其他工作。但是,由于整个解析思路是在一个循环中,因此会对同一个字符串生成多个 malloc。我只能释放一次 nameTemp,但该名称上有多个 mallocs。如何一遍又一遍地重复使用 nameTemp 而不会造成任何泄漏?

这是分配了 nameTemp 的一段代码(在函数name() 中):

 /* Make sure temp is not NULL before mallocing */
    if(temp[0] != '\0')
    {
        returnName = malloc(sizeof(char)*strlen(temp)+1);
        strncpy(returnName, temp, strlen(temp)+1);
        temp[0] = '\0';
        return returnName;
    }

如果有一些不清楚的地方,我深表歉意。我尽量笼统地说,如果您需要更多说明,请告诉我。

【问题讨论】:

    标签: c malloc realloc


    【解决方案1】:

    malloc() 不跟踪分配的块。您需要找到所有处理完您请求的内存的地方,并在那里free()

    如果我正确阅读了您的代码,那将在您的 while 循环主体的末尾。

    编辑:拉起 cmets。

    尝试使用您已经free()'d 的内存块是未定义的行为。

    然而,你用来保持块句柄的指针只是一个普通的指针,在你将它传递给free()之后不会过时。事实上,它根本不会让步,因为free() 会复制它。

    因此,在将指针传递给free() 之后,通常会看到将指针设置为NULL,以确保不会意外重用现在不可用的块。

    然后,您可以像往常一样很好地重用它作为malloc() 返回的全新块的句柄。

    【讨论】:

    • 如果我将再次使用它,释放指针不是非法的吗?如果我将 free(tempName) 放在正文末尾,下次我收集参数名称时,它会给我一个错误。还是我和你不在一个页面上?
    • @Plaidypus:您将“指针”(这是一个指向某处内存的变量)与实际分配的内存块混淆了。两次释放同一块内存是非法的。但是您可以将变量重用于不同的事情,并且在这样的循环中,它非常有意义。
    • @Plaidypus 不,那很好。释放后使用相同的指针 address 是未定义的行为(除非malloc 再次返回它,这是完全可能的),但包含指针地址的变量具有自动存储持续时间和在函数退出之前可用。
    • @BenZotto 这很有道理!我忘记了循环之外的free(nameTemp),这给我带来了问题。谢谢大家的解释。我应该认真花一个晚上阅读 C 中的动态内存。
    • @Plaidypus 一旦你了解了动态内存和指针的工作原理,你就会看到很多 C 语言。它是一种很小的语言!
    【解决方案2】:

    nameTemp = name(c); 导致不可避免的泄漏,因为 nameTemp 存储了一个指针,该指针没有保存在其他地方并且此时也没有释放。

    有很多选项可以避免这种情况(取决于您要达到的目标以及您愿意更改代码结构的程度)。

    三种可能性(从代码更改最少到最多排序):

    1. 在分配内存之前释放内存(并在程序结束时再次释放)
    free(nameTemp);
    nameTemp = name(c);
    
    1. 内存过时时释放内存
    /* Value state */
    if((isalnum(c)) && hasName == 1 && hasEqual == 1)
    {
        getValues(c, nameTemp, pm->t_List, pm->m_List);
        hasName = 0;
        hasEqual = 0;
        free(nameTemp);
        nameTemp=NULL;
    }
    
    1. 使用通用缓冲区,在开始时分配足够大的垃圾内存并在结束时再次释放。
    char* nameTemp;
    nameTemp = (char*)malloc(512); //Or any other size, just check that its actually big enough before writing to it, otherwise buffer overflow errors will occur.
    
    // Somwhere in your program
    write_name( nameTemp, 512 , c ); // Pass the buffer to be filled by the function, instead of returning a new pointer.
    
    // At the end of your program
    free(nameTemp);
    nameTemp = NULL; //Prevent access of freed memory.
    

    【讨论】:

      猜你喜欢
      • 2016-04-03
      • 1970-01-01
      • 2012-05-29
      • 2014-05-12
      • 2019-11-11
      • 2020-05-01
      • 2012-04-08
      • 2021-10-04
      • 1970-01-01
      相关资源
      最近更新 更多