【问题标题】:C - Unable to free allocated memoryC - 无法释放分配的内存
【发布时间】:2011-07-19 10:33:39
【问题描述】:

我目前正在开发的应用程序有问题。在这个程序中,我必须从文本文件中读取大量(数十亿)数据并进行管理,但由于这是一个两个学生的项目,所以阅读部分将由我的伙伴开发。出于测试原因,我编写了一个小程序来生成伪随机结构来代替我的伙伴所做的事情。

问题如下:大量生成的数据(由于冗余)可以被丢弃以释放其内存。但即使调用 free() 函数,内存使用量也在不断增长。所以我尝试开发一个调试应用程序,它可以简单地生成一大块数据并立即释放它。并重复数千次。 好吧,我无法理解原因,但分配给进程的内存增长到 ~1.8 GB 内存然后崩溃。 为什么?最奇怪的事情是,当进程崩溃时,malloc 不会返回 NULL 指针,因为当 readCycles == 6008 并绕过 NULL 检查时进程总是崩溃。

我已经在 StackOverflow 上阅读了其他相关主题,并且我理解了为什么 free() 不会减少分配给我的进程的内存。没关系。但是为什么内存使用量不断增长? malloc 不应该分配以前释放的内存而不是不断请求新的吗?

这是我的代码中最相关的部分:

#define NREAD 1000
#define READCYCLES 10000
#define N_ALPHA_ILLUMINA 7
#define N_ALPHA_SOLID 5
#define SEQLEN 76

typedef struct{
    char* leftDNA;
    char* leftQuality;
    unsigned long int leftRow;
    char* rightDNA;
    char* rightQuality;
    unsigned long int rightRow;
} MatePair;


unsigned long int readCycles = 0;


MatePair* readStream(MatePair* inputStream, short* eof, unsigned long int* inputSize){

    double r;
    unsigned long int i, j;
    unsigned long int leftRow;
    int alphabet[] = {'A', 'C', 'G', 'T', 'N'};
    inputStream = (MatePair*) malloc (sizeof(MatePair) * (NREAD + 1));
    printf("%d\n", readCycles);
    if (inputStream == NULL){
        (*eof) = 1;
        return;
    }

    for (i = 0; i < NREAD; i++){
        leftRow = readCycles * NREAD + i;
        inputStream[i].leftDNA = (char*) malloc (SEQLEN);
        inputStream[i].rightDNA = (char*) malloc (SEQLEN);
        inputStream[i].leftQuality = (char*) malloc (SEQLEN);
        inputStream[i].rightQuality = (char*) malloc (SEQLEN);
        for (j = 0; j < SEQLEN; j++){
            r = rand() / (RAND_MAX + 1);
            inputStream[i].leftDNA[j] = alphabet[(int)(r * 5)];
            inputStream[i].rightDNA[j] = alphabet[(int)(r * 5)];
            inputStream[i].leftQuality[j] = (char) 64 + (int)(r * 60);
            inputStream[i].rightQuality[j] = (char) 64 + (int)(r * 60);
        }
        inputStream[i].leftDNA[SEQLEN - 1] = '\0';
        inputStream[i].rightDNA[SEQLEN - 1] = '\0';
        inputStream[i].leftQuality[SEQLEN - 1] = '\0';
        inputStream[i].rightQuality[SEQLEN - 1] = '\0';
        inputStream[i].leftRow = leftRow;
        inputStream[i].rightRow = leftRow;
    }

    inputStream[i].leftRow = -1;

    readCycles++;
    (*inputSize) = NREAD;
    (*eof) = readCycles > READCYCLES;

    return inputStream;

}


int main(int argc, char* argv[]){

    short eof = 0;
    unsigned long int inputSize = 0;
    MatePair* inputStream = NULL;

    while (!eof){
        inputStream = readStream(inputStream, &eof, &inputSize);
        free(inputStream);
        inputStream = NULL;
    }

    return 0;

}

我忘记提了,但是在发帖之前,我没有调用 free(inputStream),而是尝试调用 freeMemory(inputStream)。不过,不确定这是否是正确的做法。

void freeMemory(MatePair* memblock){

    for ( ; memblock->leftRow != 1; memblock++){
        free(memblock -> leftDNA);
        free(memblock -> leftQuality);
        free(memblock -> rightDNA);
        free(memblock -> rightQuality);
    }

}

【问题讨论】:

  • 尝试为所有malloc 调用添加检查并使用valgrind 运行程序。也不是你的问题,但r = rand() / (RAND_MAX + 1) 总是会是0,除非你在划分之前给double 添加一个演员表。
  • 这里有几个内存泄漏,分配给 inputstream[i].leftDNA 等的内存在哪里释放。
  • 是的,我已经注意到(双重)的东西,忘记修改它,因为我更担心内存泄漏的事情:)
  • 我建议将 DNA 序列重新编码为 char 数组(例如 char leftDNA[SEQLEN])。这样,您可以一次性分配结构数组,而不是分多个步骤进行。要完全跳过动态内存分配,请在调用 readStream() 之前在堆栈上声明结构数组,并将其传递给 readStream()。我假设您的系统不是嵌入式系统,并且可以处理大约 300 kb 的堆栈。
  • 问题是 readStream() 只是一个调试存根,在最终的应用程序中,直到我读取(并处理)第一个文本文件的第一行,我才会知道 SEQLEN 中的值,据我所知,这是唯一的方法,不是吗? (我可能错了,距离我上一个 C 程序已经有好几年了,我从来都不是它的专家)

标签: c memory-management crash free


【解决方案1】:

内存泄漏。您调用了多少个“malloc()”,必须使用多少个“free()”来释放堆上所有已分配的内存。

因此,

inputStream[i].leftDNA = (char*) malloc (SEQLEN);
inputStream[i].rightDNA = (char*) malloc (SEQLEN);
inputStream[i].leftQuality = (char*) malloc (SEQLEN);
inputStream[i].rightQuality = (char*) malloc (SEQLEN);

这些 'malloc()' 函数必须与 free() 配对。

【讨论】:

  • 此外,您的程序中还存在一些缺陷。首先,在if(inputStream == NULL){(*eof) = 1; return;}中,'return'可能是'return NULL';其次,也许你应该在 malloc() 失败时处理这个问题。
  • eof = 1 应该通过 while 循环检查失败来结束程序本身,这就是我不打扰 return 语句的原因。
  • 但是,这不是一个好的程序风格:) 读者如果不看完整个程序会感到困惑~
【解决方案2】:

您没有释放在读取循环中分配的所有成员,因此您每次都会丢失内存。请记住,您必须释放您使用 malloc 分配的所有内容,而不仅仅是您的数组。

好的,看看你的编辑,你的 freeMemory 仍然是错误的。试试这个;

void freeMemory(MatePair* inputStream)
{
    for (i = 0; i < NREAD; i++){
        free(inputStream[i].leftDNA);
        free(inputStream[i].leftQuality);
        free(inputStream[i].rightDNA);
        free(inputStream[i].rightQuality);
    }
    free (inputStream);
  }

您的 free(memblock) 在循环中,它不应该在循环中,我倾向于在释放时使用与 mallocing 相同的迭代序列。您还需要在每个 malloc 之后进行错误检查,并在此时决定如何处理 NULL。

【讨论】:

  • 对不起,忘了说,编辑了我的帖子。但是,不确定这是不是正确的方法。
  • 好吧,看来你和 Stan 都是对的,正如我自己所怀疑的那样。使用 freeMemory() 函数,应用程序崩溃了,因为我正在检查 leftRow 是否为 1,这意味着只释放了前两个结构。该死的错字!!应该是-1...谢谢你们的帮助,很抱歉这个愚蠢的问题...
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 2018-03-26
  • 2013-02-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多