C 中 free() 函数的问题和内存泄漏

Problem with free() function in C and memory-leaks

我有一个关于在 C 中使用 free() 释放内存的问题。 我的程序使用矩阵生成随机家谱树。根据家庭成员的数量,这个矩阵可能非常庞大。在我决定生成不止一棵树之前,该程序似乎运行良好。我注意到生成大约 100 棵树会导致我的 8GB RAM 被填满!我确定我可以编写更好的代码来减少内存需求,但我的问题仍然存在。 我使用 free() 来释放内存并且没有错误。我安装了 Valgrind 来查看发生了什么,它说每棵树肯定丢失了大约 1 亿字节。这意味着 free() 不能正常工作。我现在不知道问题出在哪里。我 link 一些我认为与问题相关的函数。

typedef struct{
   int f_id;
   char f_name[L_NAMES];
   int generations;
   int n_members;
   type_people *members;
   int_mtx *mtx;
}type_family;

上面的结构是给家庭的。

typedef struct temp{
   int p_id;
   char name[L_NAMES];
   char f_name[L_NAMES];
   int generation;
   int n_sons;
   struct temp **sons; 
   int f_id;
   int sex;
   int age;
}type_people;

这是给会员的。

typedef struct{
   int i;
   int j;
   int **val;
}int_mtx;

和矩阵。 在主要我调用函数来初始化树:

type_family *family_a;
family_a = malloc(sizeof(type_family));
family_a = init_family_n_gen(family_a, 6);

这是 init_family_n_gen() 的第一部分:

type_family *init_family_n_gen(type_family *family, int n){
   ...
   family->members = malloc(max_people * sizeof(type_people));
   family->mtx = mtxcalloc(family->mtx, max_people, max_people - 1);
   ...

此代码用于初始化矩阵的 mtxcalloc:

int_mtx *mtxcalloc(int_mtx *mtx, int i, int j){
   mtx = malloc(sizeof(int_mtx));
   mtx->i = i;
   mtx->j = j;
   mtx->val = malloc(i * sizeof(int *));
   for(int a = 0; a < i; a++){
      mtx->val[a] = malloc(j * sizeof(int));
      for(int b = 0; b < j; b++){
         mtx->val[a][b] = 0;
      }
   }
   return mtx;
 }

并结束解除分配家庭的代码:

void free_family(type_family *family){
   for(int m = 0; m < family->n_members; m++){
     if(family->members[m].n_sons != 0){
        free(family->members[m].sons);
     }
   }
   mtxfree(family->mtx);
   free(family->members);
}

以及解除分配矩阵的那个:

void mtxfree(int_mtx *mtx){
   for(int i = 0; i < mtx->i; i++){
      free(mtx->val[i]);
   }
   free(mtx->val);
   free(mtx);
}

Screen capture of Valgrind output 所以每次我需要重新生成家庭时我都会调用 free_family(family_a) 但内存仍然增加。 (在上面的照片中,如果我重新生成家庭 50 次,字节数将变为 10 亿)。 感谢支持!

已编辑

我做了一个最小的可复制示例来模拟我的原始代码。结构和变量是相同的,但我根据 Weather Vane 更改了函数:它们都是 void 并且我将双 ** 传递给它们。 init_family_n_gen 变为:

void init_family(type_family **f){
  type_family *family = malloc(sizeof(type_family));
  family->members = malloc(100 * sizeof(type_people));
  for(int m = 0; m < 100; m++){
     family->members[m].n_sons = 0;
  }
  mtxcalloc(&family->mtx, 100, 99);
  family->mtx->val[0][1] = 7;
  family->mtx->val[9][8] = 1;
  mtxrealloc(&family->mtx, 5, 4);
  *f = family;
}

主要是:

type_family *family_a;
init_family(&family_a);
free_family(&family_a);

我唯一添加的就是这个功能(代码对吗?):

void mtxrealloc(int_mtx **mtx, int i, int j){
   (*mtx)->i = i;
   (*mtx)->j = j;
   (*mtx)->val = realloc((*mtx)->val, (*mtx)->i * sizeof(int *));
   for(int a = 0; a < (*mtx)->i; a++){
    (*mtx)->val[a] = realloc((*mtx)->val[a], (*mtx)->j * sizeof(int));
   }
}

我注意到当我使用 realloc 函数时会出现问题,但我不明白为什么。我 link 带有和不带有函数 mtxrealloc 的 Valgrind 图像。 (我看到还有一个 48 字节的泄漏......)。 Valgrind with realloc Valgrind without realloc 再次感谢您的支持!

这个:

init_family(&family_a);

导致 mtxcalloc 中的代码执行:

mtx->val = malloc(i * sizeof(int *));
for(int a = 0; a < i; a++){
   mtx->val[a] = malloc(j * sizeof(int));
   for(int b = 0; b < j; b++){
      mtx->val[a][b] = 0;
   }
}

,其中 ij = 100, 99。也就是说,您为 100 个指针分配 space,并且为每个指针分配 space 99 int 秒。然后可以通过 family_a->mtx.

访问这些内容

此后不久,您拨打了这个电话:

 mtxrealloc(&family->mtx, 5, 4);

,其中包括:

   (*mtx)->val = realloc((*mtx)->val, (*mtx)->i * sizeof(int *));

丢失所有指针 (*mtx)->val[5](*mtx)->val[99]每个指针都是分配给 space 的唯一指针,足够 99 ints 。总的来说,在您对正在准备的对象执行任何计算之前,足够 space 9405 ints 已经泄漏。

目前还不清楚为什么要过度分配,只是为了立即(尝试)释放多余的部分,但这也许是代码简化的产物。最好想出一种方法来确定你提前需要多少 space,然后一开始只分配那么多。但是如果你确实需要重新分配这个特定的数据,那么你需要先释放每个将丢失的 (*mtx)->val[x] 。当然,如果您要重新分配更大的内存,那么您需要分配/重新分配 (*mtx)->val[x].

all