简体   繁体   中英

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

I've a problem about deallocating memory using free() in C. My program generates a random genealogic tree using a matrix. This matrix can be very huge depending on the number of family members. The program seemed to work fine until I decided to generate more than one tree. I noticed that generating about 100 trees causes my 8GB RAM to fill, I'm sure I can make a better code to reduce the demand of memory. but my problem remains. I use free() to deallocate memory and there's no error. I installed Valgrind to se what's happening and it says that about 100 million byte per tree are definitely lost. This means that free() doesn't work fine. I don't now where is the problem. I link some functions that I think are correlated to the problem.

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

The struct above is for the 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;

This is for the members.

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

And the matrix. In the main i call the function to initialize the tree:

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

This is the frist part of 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);
   ...

This code is for mtxcalloc that initializes the matrix:

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;
 }

And to conclude the code to deallocate the family:

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);
}

And the one to deallocate the matrix:

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 So I call the free_family(family_a) every time i need to regenerate the family but the memory still increases. (In the photo above the number of byte become 1 billion if i regenerate the family for 50 times). Thanks for the support!

EDITED

I made a minimal reproducible example that emulates my original code. The structs and variables are the same but I changed the functions according to Weather Vane: they are all void and I pass them the double **. The init_family_n_gen becomes:

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;
}

The main is:

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

The only thing I added is this function(Is the code right?):

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));
   }
}

I noticed that the problem occours when i use the realloc function and i can't figure why. I link the images of Valgrind with and without the function mtxrealloc. (I see that there is aslo a 48 byte leak...). Valgrind with realloc Valgrind without realloc Thanks again for your support!

This:

 init_family(&family_a);

Causes this code from mtxcalloc to execute:

 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; } }

, with i , j = 100, 99. That is, you allocate space for 100 pointers, and for each one, you allocate space for 99 int s. These are then accessible via family_a->mtx .

Very shortly thereafter, you make this call:

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

, which does this, among other things:

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

That loses all the pointers (*mtx)->val[5] through (*mtx)->val[99] , each of which is the sole pointer to allocated space sufficient for 99 int s . Overall, sufficient space for 9405 int s is leaked before you even perform any computations with the object you are preparing.

It is unclear why you overallocate, just to immediately (attempt to) free the excess, but perhaps that's an artifact of your code simplification. It would be much better to come up with a way to determine how much space you need in advance, and then allocate only that much in the first place. But if you do need to reallocate this particular data, then you need to first free each of the (*mtx)->val[x] that will be lost. Of course, if you were going to reallocate larger, then you would need to allocate / reallocate all of the (*mtx)->val[x] .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM