簡體   English   中英

Valgrind檢測到可到達的泄漏,它們在哪里?

[英]Valgrind detects reachable leaks, where are they?

我使用鏈表在C中編寫了一個簡單堆棧的小型實現。 該應用程序在對gdb和valgrind進行了一些大驚小怪之后才能正常工作。 但是,我注意到valgrind在程序終止時報告了許多“仍可到達”的泄漏。

經過一番谷歌搜索后,我發現這些類型的泄漏不是問題,我通常不必擔心它們。 好吧,這是個好消息! 唯一的是,我真的很想了解valgrind為什么會看到這些泄漏及其出現的位置。 在我第一次通過此應用程序時,我非常努力地努力釋放所有分配的內存。 我錯過了什么? valgrind看到這些分配在哪里,但我看不到?

我已經凝視了一段時間,盡管以這種方式擺弄代碼,卻空手而歸。 希望大家能在這項工作中對我有所幫助。

我已將應用程序簡化為一個最小的示例,該示例將顯示我正在觀察的泄漏。 它只是初始化堆棧,然后立即銷毀它並退出。

// simple stack implementation
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>

/*--- data structure in a stack item ---*/
struct data {
    char * message;
};

/*--- stack item structure ---*/
struct item {
    struct data * my_data;
    struct item * next;
};

/*--- stack data structure ---*/
struct stack {
    int initialized;
    int empty;
    struct item * head;
};
struct stack * my_stack;

/*--- create a new stack data structure with provided initial data ---*/
int
create_stack(struct data  ** initial_items, int num_items) {

    //allocate memory for the stack structure itself
    my_stack = (struct stack *) malloc(sizeof(struct stack));
    if(!my_stack) return -1;
    my_stack->empty = 1;
    my_stack ->initialized = 0;

    if(num_items) {
        //allocate memory for the head of the list first
        my_stack->head = (struct item *) malloc(sizeof(struct item));
        if(!my_stack->head) return -1;
        my_stack->head->my_data = initial_items[0];
        my_stack->head->next = NULL;
        struct item * tracker = my_stack->head;

        //fill the stack with elements containing the provided data
        int i = 1;
        for(; i < (num_items); i++) {
            tracker->next = (struct item *) malloc(sizeof(struct item));
            tracker = tracker->next;
            if(!tracker) return -1;
            tracker->my_data = initial_items[i];
            tracker->next = NULL;
        }

        //no longer empty
        my_stack->empty = 0;
    }

    //set initialized flag & return
    my_stack->initialized = 1;
    return 0;
}

/*--- destroy the stack by recursively freeing nodes ---*/
int
destroy_stack(struct item * recurse) {

    //if the starting node is valid, begin
    if(recurse) {
        //if the current node links to another
        if(recurse->next)
            //recurse on the next node
            destroy_stack(recurse->next);
        else
            //otherwise we hit the end, free the node
            free(recurse);
    }
    //the starting node is invalid, just free the stack itself
    else {
        free(my_stack);
    }

    return 0;
}

/*--- test wrapper ---*/
int
main(int argc, char **argv) {

    //initialize 10 element list of data structures to fill the stack items with
    int i = 0;
    int length = 10;
    struct data ** initial_values = (struct data **) malloc(length*sizeof(struct data *));

    //set each data element's value to i
    for(; i < length; i++) {
        char temp[16];
        sprintf(temp, "%d", i);
        initial_values[i] = (struct data *) malloc(sizeof(struct data));
        initial_values[i]->message = strdup(temp);
    }

    //simple test case
    //create a stack with the generated initial data, then destroy it
    assert( !create_stack(initial_values, length) );
    assert( !destroy_stack(my_stack->head) );

    //free the string data our stack nodes were pointing to
    i = 0;
    while(i < length) {
        free(initial_values[i]->message);
        free(initial_values[i]);
        i += 1;
    }
    free(initial_values);

    return 0;
}

通過valgrind運行此命令將生成以下已標識的未釋放塊:

(trusty)kin3tix@localhost:~/C Practice/Data Structures$ valgrind --leak-check=full --show-leak-kinds=all ./stack_leak_test
==19340== Memcheck, a memory error detector
==19340== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==19340== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==19340== Command: ./stack_leak_test
==19340== 
==19340== 
==19340== HEAP SUMMARY:
==19340==     in use at exit: 168 bytes in 10 blocks
==19340==   total heap usage: 32 allocs, 22 frees, 364 bytes allocated
==19340== 
==19340== 16 bytes in 1 blocks are still reachable in loss record 1 of 3
==19340==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340==    by 0x400739: create_stack (stack_leak_test.c:40)
==19340==    by 0x40093B: main (stack_leak_test.c:95)
==19340== 
==19340== 24 bytes in 1 blocks are still reachable in loss record 2 of 3
==19340==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340==    by 0x4006E6: create_stack (stack_leak_test.c:33)
==19340==    by 0x40093B: main (stack_leak_test.c:95)
==19340== 
==19340== 128 bytes in 8 blocks are still reachable in loss record 3 of 3
==19340==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19340==    by 0x4007A1: create_stack (stack_leak_test.c:48)
==19340==    by 0x40093B: main (stack_leak_test.c:95)
==19340== 
==19340== LEAK SUMMARY:
==19340==    definitely lost: 0 bytes in 0 blocks
==19340==    indirectly lost: 0 bytes in 0 blocks
==19340==      possibly lost: 0 bytes in 0 blocks
==19340==    still reachable: 168 bytes in 10 blocks
==19340==         suppressed: 0 bytes in 0 blocks
==19340== 
==19340== For counts of detected and suppressed errors, rerun with: -v
==19340== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

它們似乎都源於“ create_stack”,但是據我所知,destroy函數應該捕獲我分配的所有內容。 我在這里想念什么?

您的銷毀邏輯試圖將兩個任務(刪除堆棧對象及其項)以遞歸方式組合在一個函數中。 更糟的是, else國家不應該存在 您已經確定要坐在動態節點上( recurse )。 需要刪除。 是否有next不是由當前深度決定的。 在下一個遞歸深度中將予以解決。

坦白地說,如果您創建一個幫助程序來擦除鏈表,並作為單獨的包裝器來進行上述操作(與堆棧本身相同),則這要簡單得多:

/*--- destroy linked list nodes recursively ---*/
static void destroy_stack_items(struct item *item)
{
    if (item)
    {
        destroy_stack_items(item->next);
        free(item);
    }
}

/*--- destroy the stack by recursively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
    if (s)
    {
        destroy_stack_items(s->head);
        free(s);
    }
    return 0
}

並簡單地調用為:

destroy_stack(my_stack);

就我個人而言,我會反復進行此操作(因此在此過程中刪除幫助程序),但是我確定您有其他理由。 例如:

/*--- destroy the stack by iteratively freeing nodes ---*/
int destroy_stack(struct stack *s)
{
    if (s)
    {
        while (s->head)
        {
            struct item *tmp = s->head;
            s->head = tmp->next;
            free(tmp);
        }
        free(s);
    }
    return 0
}

祝你好運。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM