简体   繁体   中英

C freeing multi-dimensional array inside a struct seems incorrect

I've seen another question for allocating and freeing multi-dimensional arrays, but I suspect that it does not free correctly. For testing I made this small code extracted from my main code. I compiled it under MacOS X.10 with XCode or gcc 4.9 with same results:

Faulty code

It runs 200000 times and the memory consumption grows up to 20GB!:

#include <stdlib.h>
typedef struct{
    int lonSize;
    int latSize;
    double **grid;
}raf09_grid_t;
static raf09_grid_t raf09_grid;

void free_raf09_grid() {
    if (raf09_grid.grid != NULL) {
            int i;
                for (i = 0; i < raf09_grid.lonSize; ++i) {
                    free(raf09_grid.grid[i]);
                }
                free(raf09_grid.grid);
    }
    raf09_grid.latSize = 0;
    raf09_grid.lonSize = 0;
}

void get_raf09_grid() {
    int nbElLat=381;
    int nbElLon=421;
    raf09_grid.grid = malloc(nbElLon*sizeof(double*));
    int it;
    for(it=0;it<nbElLon;it++)
          raf09_grid.grid[it] = malloc(nbElLat*sizeof(double));
    int i,j;
    for(i=0;i<420;i++) {
        for(j=0;j<380;j++) {
           raf09_grid.grid[i][j]=0.0;
        }
    }
}

int main (int argc, char *argv[]) {
   int i=0;
   for (i=0;i<20000;i++) {
       get_raf09_grid();
       free_raf09_grid();
   }
   return 0;
}

I'm newbie so I suspect that my freeing is not correct...

Corrected code

With your help I corrected my code, it is now corrects and takes only 10M in ram:

#include <stdlib.h>
typedef struct{
    int lonSize;
    int latSize;
    double **grid;
}raf09_grid_t;
static raf09_grid_t raf09_grid;

void free_raf09_grid() {
    if (raf09_grid.grid != NULL) {
            int i;
                for (i = 0; i < raf09_grid.lonSize; ++i) {
                    free(raf09_grid.grid[i]);
                }
                free(raf09_grid.grid);
    }
    raf09_grid.latSize = 0;
    raf09_grid.lonSize = 0;
}

void get_raf09_grid() {
    raf09_grid.latSize=381;
    raf09_grid.lonSize=421;
    raf09_grid.grid = malloc(raf09_grid.lonSize*sizeof(double*));
    int it;
    for(it=0;it<raf09_grid.lonSize;it++)
          raf09_grid.grid[it] = malloc(raf09_grid.latSize*sizeof(double));
    int i,j;
    for(i=0;i<420;i++) {
        for(j=0;j<380;j++) {
           raf09_grid.grid[i][j]=0.0;
        }
    }
}

int main (int argc, char *argv[]) {
   int i=0;
   for (i=0;i<20000;i++) {
       get_raf09_grid();
       free_raf09_grid();
   }
   return 0;
}

Valgrind is an invaluable tool in tracing memory leaks. Compiling your source code with debug information, and running it with:

valgrind --leak-check=full -v ./a.out

will give the following summary:

==7033== HEAP SUMMARY:
==7033==     in use at exit: 1,283,208,000 bytes in 421,000 blocks
==7033==   total heap usage: 422,000 allocs, 1,000 frees, 1,286,576,000 bytes allocated
==7033== 
==7033== Searching for pointers to 421,000 not-freed blocks
==7033== Checked 92,040 bytes
==7033== 
==7033== 18,288 bytes in 6 blocks are possibly lost in loss record 1 of 2
==7033==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7033==    by 0x400611: get_raf09_grid (grid.c:27)
==7033==    by 0x4006A8: main (grid.c:39)
==7033== 
==7033== 1,283,189,712 bytes in 420,994 blocks are definitely lost in loss record 2 of 2
==7033==    at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7033==    by 0x400611: get_raf09_grid (grid.c:27)
==7033==    by 0x4006A8: main (grid.c:39)
==7033== 
==7033== LEAK SUMMARY:
==7033==    definitely lost: 1,283,189,712 bytes in 420,994 blocks
==7033==    indirectly lost: 0 bytes in 0 blocks
==7033==      possibly lost: 18,288 bytes in 6 blocks
==7033==    still reachable: 0 bytes in 0 blocks
==7033==         suppressed: 0 bytes in 0 blocks
==7033== 
==7033== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)
--7033-- 
--7033-- used_suppression:      2 dl-hack3-cond-1
==7033== 
==7033== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 2 from 2)

The link to line 27 shows that there is a problem with this statement:

raf09_grid.grid[it] = malloc(nbElLat*sizeof(double));

You are allocating more memory here than is being freed later in the program.

Update the raf09_grid.lonSize variable in get_raf09_grid() to equal nbElLon , and it fixes the problem.

In general, every malloc should have a corresponding free . Once you know which malloc is leaking, then you can find the code that is supposed to free that variable, and debug from there.

Note: I reduced the loop from 20000 to 1000, but it will give you the same information.

After reading through yoiur question, here are a few suggestions:

In the code:

for(i=0;i<420;i++) {
    for(j=0;j<380;j++) {
       raf09_grid.grid[i][j]=0.0;
    }

you are looping i and j for 420 and 380, while you've defined :

int nbElLat=381;
int nbElLon=421;

So, you never process the 420th iteration for the Longitudes. The same with missing out on the 380th loop for Latitude. If that's a desirable thing, its fine, else you should fix it to something like this:

for(i=0;i<nbElLon;i++) { //better use macros or variable names than just plain magic numbers
    for(j=0;j<nbElLat;j++) {
       raf09_grid.grid[i][j]=0.0;
    }

Second, in your free_raf09_grid() function, you use:

for (i = 0; i < raf09_grid.lonSize; ++i) {

but you haven't initialized that variable anywhere.

Perhaps in function get_raf09_grid() just before the declaration of int i,j do this:

raf09_grid.lonSize = nbElLon; 
raf09_grid.latSize = nbElLat;

The third important one. In the lines below:

raf09_grid.grid = malloc(nbElLon*sizeof(double*));
int it;
for(it=0;it<nbElLon;it++)
      raf09_grid.grid[it] = malloc(nbElLat*sizeof(double));

you should check if the malloc s have returned success or not aka check for NULL.

您的for循环使用lonSize作为参数,但是在任何地方都不会更新

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