C 语言中 valgrind 的幻影泄漏

Phantom leaks with valgrind in C

提问人:lbsmart 提问时间:3/3/2023 更新时间:3/3/2023 访问量:51

问:

我正在编写一个简单的数组。我怎么想,在泄漏方面做正确的事。但 valgrind 不这么认为。为什么?那个幻影泄漏只是因为我做了更多的 malloc 然后免费?

法典:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CAPACITY_INCREACE(arr) ((int)(arr->capacity * 1.5f))
#define CAPACITY_DEFAULT 5

typedef struct array
{
    int capacity;
    int size;
    int* arr;
} array;

array* create_array()
{
    array* arr = (array*)malloc(sizeof(array));
    arr->capacity = CAPACITY_DEFAULT;
    arr->size = 0;
    arr->arr = (int*)malloc(arr->capacity * sizeof(int));
    return arr;
}

void print_array(array *arr)
{
    printf("array, size - %d, capacity - %d\n", arr->size, arr->capacity);
    for(int i = 0; i < arr->size; ++i)
        printf("%d ", arr->arr[i]);
    printf("\n");
}

void realloc_array(array* arr, int size)
{
    int* new_arr = (int*)malloc(size * sizeof(int));
    memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
    arr->arr = new_arr;
}

void add(array* arr, int element)
{
    if((arr->size + 1) <= arr->capacity)
    {
        arr->arr[arr->size++] = element;
        return;
    }
    
    arr->capacity = CAPACITY_INCREACE(arr);
    realloc_array(arr, arr->capacity);
    arr->arr[arr->size++] = element;
}

void delete_array(array *arr)
{
    free(arr->arr);
    free(arr);
}

int main(int argc, int** argv)
{
    array* arr = create_array();
    for(int i = 0; i < 8; i++)
        add(arr, i);
    print_array(arr);

    delete_array(arr);
    return 0;
}

Valgrind 运行和程序编译

gcc -g array.c && ./a.out
valgrind --leak-check=full -s ./a.out

来自 valgrind 的信息,他向我展示了哪里,但不幸的是我不明白我做错了什么:

HEAP SUMMARY:
    in use at exit: 48 bytes in 2 blocks
    total heap usage: 5 allocs, 3 frees, 1,128 bytes allocated

 20 bytes in 1 blocks are definitely lost in loss record 1 of 2
    by 0x10920B: create_array (array.c:21)
    by 0x109443: main (array.c:71)
 
 28 bytes in 1 blocks are definitely lost in loss record 2 of 2
    by 0x10930C: realloc_array (array.c:43)
    by 0x1093CD: add (array.c:57)
    by 0x10946D: main (array.c:74)
 
 LEAK SUMMARY:
    definitely lost: 48 bytes in 2 blocks
    indirectly lost: 0 bytes in 0 blocks
      possibly lost: 0 bytes in 0 blocks
    still reachable: 0 bytes in 0 blocks
         suppressed: 0 bytes in 0 blocks
c 马洛克 ·瓦尔格林德

评论

2赞 yano 3/3/2023
我做的 malloc免费.这就是你的答案。如果你到最后还没记错,valgrind 会理所当然地抱怨。mallocfree
1赞 yano 3/3/2023
这可能不是一个实际问题。操作系统将在进程退出时清理进程分配的所有内存,因此,如果您执行一次将持续所有进程的内存,则不这样做不会有真正的问题。事实上,我已经看到高代表 SO 用户主张清理内存,因为它只是需要编写、测试、调试等更多代码。但预计 valgrind 会在这些情况下抱怨。mallocfree
1赞 Fe2O3 3/3/2023
if((arr->size + 1) <= arr->capacity) ==> if( arr->size < arr->capacity )...简单多了。
0赞 Paul Floyd 3/3/2023
@yano,如果允许泄漏,则存在两种危险。首先是您的应用程序可能会耗尽内存。其次,如果你有大量的泄漏,那么检测新的泄漏比你保持零泄漏政策要困难得多。
0赞 Paul Floyd 3/3/2023
@yano也不要太相信一个高 SO 代表。这通常只是作为早期贡献者的滚雪球效应。

答:

2赞 MikeCAT 3/3/2023 #1

函数

void realloc_array(array* arr, int size)
{
    int* new_arr = (int*)malloc(size * sizeof(int));
    memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
    arr->arr = new_arr;
}

在没有释放的情况下扔掉原始缓冲区。arr->arr

添加调用以避免内存泄漏。free()

void realloc_array(array* arr, int size)
{
    int* new_arr = (int*)malloc(size * sizeof(int));
    memcpy((void*)new_arr, arr->arr, arr->size * sizeof(int));
    free(arr->arr); /* add this */
    arr->arr = new_arr;
}

或使用标准.realloc()

void realloc_array(array* arr, int size)
{
    int* new_arr = realloc(arr->arr, size * sizeof(int));
    if (new_arr == NULL) exit(1);
    arr->arr = new_arr;
}

另请注意,选择家庭结果被认为是一种不好的做法malloc()

评论

0赞 Paul Floyd 3/3/2023
你必须在 C++ 中强制转换。问题是针对 C,我同意你不应该投射。不要混用 C 和 C++ - 它们共享传统并且相似,但这并不能使它们相同。