【问题标题】:C - Memory leak even with all allocs free'dC - 即使所有分配都已释放,内存泄漏
【发布时间】:2017-03-10 05:36:15
【问题描述】:

我的程序基本上是获取用户输入并比较作为彼此字谜的单词。我已经在 Unix 中编译了该程序并针对它运行了 valgrind -v,但是我不明白当所有堆分配在退出时都被释放时,我的内存泄漏可能来自哪里。这是我的主要方法和 valgrind 输出。

int main()
{
    // Create a head node for the linked list, and a newNode variable to 
    //add to the list     
    struct node *newNode;
    struct node *head = malloc(sizeof(struct node));
    if(head == NULL)
    {
        fprintf(stderr, "Out of memory. Exiting.\n");
        return 1;
    }
    head->next = NULL;

    // For user input
    char *input = NULL;
    char *data;
    size_t len = 0;

    // Read a line in at a time
    while(getline(&input, &len, stdin) != EOF)
    {
        // Delete newline symbol
        input[strlen(input) - 1] = '\0';
        // Convert string to seperate words
        data = strtok(input, " ");

        // While there are more words from the sentence to read
        while(data != NULL)
        {
            // Check that its a letter
            int i, check = 0, length = strlen(data);
            for(i = 0; i < length; i++)
            {
                if(isalpha(data[i]) == 0)
                {
                    check = -1;
                    break;
                }
            }

            // If a letter, create a node, set the data, and append to the
            // to the linked list
            if(check == 0)
            {
                newNode = malloc(sizeof(struct node));
                if(newNode == NULL)
                {
                    fprintf(stderr, "Out of memory. Exiting.\n");
                    return 1;
                }

                newNode->data = data;
                newNode->next = NULL;

                if(head->next == NULL)
                {
                    head->next = newNode;
                }
                else
                {
                    struct node *current = head;
                    while(current->next != NULL){
                        current = current->next;
                    }

                    current->next = newNode;
                }
            }
            // If not a letter, skip the node creation and output error
            else
            {
                fprintf(stderr, "Bad word %s\n", data);
            }

            data = strtok(NULL, " ");

        }

        input = NULL;
        data  = NULL;
    }

    print_anagrams(head->next);
    // Free all mallocs and pointers
    free(newNode);
    free(head);
    free(input);
    free(data);

    return 0;
}

Valgrind 输出

==32070== Invalid free() / delete / delete[] / realloc()
==32070==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)
==32070==    by 0x400F43: main (anagrams2.c:192)
==32070==  Address 0x51fc1f0 is 0 bytes inside a block of size 120 free'd
==32070==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)
==32070==    by 0x400F0F: main (anagrams2.c:187)
==32070==
==32070==
==32070== HEAP SUMMARY:
==32070==     in use at exit: 120 bytes in 1 blocks
==32070==   total heap usage: 5 allocs, 5 frees, 288 bytes allocated
==32070==
==32070== Searching for pointers to 1 not-freed blocks
==32070== Checked 80,264 bytes
==32070==
==32070== 120 bytes in 1 blocks are definitely lost in loss record 1 of 1
==32070==    at 0x4C2AB80: malloc (in /usr/lib/valgrind
/vgpreload_memcheck-amd64-linux.so)
==32070==    by 0x4EA5F54: getdelim (iogetdelim.c:66)
==32070==    by 0x400EF9: main (anagrams2.c:131)
==32070==
==32070== LEAK SUMMARY:
==32070==    definitely lost: 120 bytes in 1 blocks
==32070==    indirectly lost: 0 bytes in 0 blocks
==32070==      possibly lost: 0 bytes in 0 blocks
==32070==    still reachable: 0 bytes in 0 blocks
==32070==         suppressed: 0 bytes in 0 blocks
==32070==
==32070== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==32070==
==32070== 1 errors in context 1 of 2:
==32070== Invalid free() / delete / delete[] / realloc()
==32070==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)
==32070==    by 0x400F43: main (anagrams2.c:192)
==32070==  Address 0x51fc1f0 is 0 bytes inside a block of size 120 free'd
==32070==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)
==32070==    by 0x400F0F: main (anagrams2.c:187)
==32070==
==32070== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

【问题讨论】:

  • 如果您使用getline 并且看到“in use at exit: 120 bytes in 1 blocks”,那么这应该会提示您无法释放(或以其他方式滥用)getline 分配的缓冲区这一事实(input 在你的情况下)。 getline 缓冲区的默认分配大小是 120-bytes

标签: c memory-leaks getline


【解决方案1】:

你的代码有两个问题:

  1. 您不应该释放data,因为它是从对strtok 的调用中返回的,并且不是分配的指针,而只是指向getline 返回的输入中的字符串的指针。(这主要导致您的无效免费错误在 Valgrind 报告中)
  2. 您在循环结束时将input 设置为NULL,因此您基本上丢失了指向getLine 返回的内存的指针。您应该在循环内的适当位置释放 input(这会导致 Valgrind 报告中出现内存泄漏错误)

【讨论】:

  • data 不是指向input 内的字符串的指针,该字符串是由getline 编辑的malloc。释放它的问题是它可能不指向getline分配的块的开头。一个很好的提示是inside a block of size 120getline 中的默认分配大小)
  • 如果他恰好有data 指向来自strtok 的第一个令牌,那么他基本上将释放input(在复制和存储data 之后他应该这样做)一个单独的内存块)。 getline 的大规则,您不能丢失对 input 分配开头的引用,否则您将无法释放 getline 分配的块。总是更好地分配新的块来存储input 的部分,这样input 可以留给getline 重用(它在后续读取时会这样做)。
  • 最好将分配的缓冲区作为输入发送到 getline。如果需要,它可能会调整它的大小。继续为多个调用发送相同的输入指针,并在退出循环后释放它。这也清楚地向代码的读者确定了谁是内存的所有者。
  • 如果你释放行,所有存储在链表中的数据指针都将被悬空。
猜你喜欢
  • 2011-12-17
  • 1970-01-01
  • 2012-06-08
  • 2016-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 2011-01-27
相关资源
最近更新 更多