C释放结构中的多维数组似乎不正确

时间:2014-08-10 11:00:47

标签: c memory-management memory-leaks malloc free

我已经看到了另一个分配和freeing多维数组的问题,但我怀疑它没有正确释放。为了测试,我从主代码中提取了这个小代码。 我使用XCode或gcc 4.9在MacOS X.10下编译它,结果相同:

代码错误

它运行200000次,内存消耗增长到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;
}

我是新手所以我怀疑我的解放是不正确的......

更正代码

在你的帮助下我更正了我的代码,它现在已经纠正,并且在ram中只需要10M:

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

3 个答案:

答案 0 :(得分:2)

Valgrind是追踪内存泄漏的宝贵工具。使用调试信息编译源代码,并使用以下命令运行:

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

将提供以下摘要:

==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)

第27行的链接显示此声明存在问题:

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

这里分配的内存比以后在程序中释放的内容要多。

raf09_grid.lonSize中的get_raf09_grid()变量更新为等于nbElLon,并解决问题。

通常,每个malloc都应该有相应的free。一旦你知道哪个malloc正在泄漏,那么你可以找到应该释放该变量的代码,并从那里进行调试。

注意:我将循环从20000减少到1000,但它会给你相同的信息。

答案 1 :(得分:2)

在阅读了yoiur问题之后,这里有一些建议:

在代码中:

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

您正在循环ij 420和380,而您已定义:

int nbElLat=381;
int nbElLon=421;

所以,你永远不会处理经度的第420次迭代。同样在Latitude的第380个循环中错过了。 如果这是一件令人向往的事情,那就好了,否则你应该把它修好为:

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

其次,在free_raf09_grid()函数中,您使用:

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

但你还没有在任何地方初始化该变量。

可能在get_raf09_grid()声明之前的函数int i,j执行此操作:

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

第三个重要的一个。 在下面的行中:

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

您应该检查malloc是否已成功返回,并检查是否为空。

答案 2 :(得分:1)

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