多次使用malloc函数为什么不行?

时间:2021-02-11 03:17:16
编了一个程序,
其中要用到很多很多数组来进行大型的矩阵计算(使用分治法递归实现,所以中间数据特别多)。

定义成静态数组已经不够用了(经测试只能支持到几百*几百的数组相乘)。
所以采用了malloc的形式,
但在运行的时候,却出现 Segmentation fault (core dumped)

经测试发现,如果我连续malloc两三次的话,程序是可以运行的,
一旦我连续malloc好多次,程序在运行的时候在某个malloc处就会出错而终止。尽管我测试的矩阵很小,不可能内存不够。

程序本身应该是没有问题的,因为若使用静态数组的话,一切正常。

这样的问题,可能是出在哪里呢?


void STRASSEN(arg)
struct thread_args *arg;
 {
    float **A12,**A21;
    float **B12,**B21;
    float **C11,**C12,**C21,**C22;
    float **MM1,**MM2;
    struct thread_args thread[7];
    int i,j;
    int n = arg->n;
    int m = n/2;

    if (n == TN) {
        MATRIX_MULTIPLY(n,arg->A,arg->B,arg->C);
    } else {

        A12=(float **)malloc(m*sizeof(float *));
        A21=(float **)malloc(m*sizeof(float *));
        B12=(float **)malloc(m*sizeof(float *));
        B21=(float **)malloc(m*sizeof(float *));
        C11=(float **)malloc(m*sizeof(float *));
        C12=(float **)malloc(m*sizeof(float *));
        C21=(float **)malloc(m*sizeof(float *));
        C22=(float **)malloc(m*sizeof(float *));
        MM1=(float **)malloc(m*sizeof(float *));
        MM2=(float **)malloc(m*sizeof(float *));
        if (NULL==A12||NULL==A21||NULL==B12||NULL==B21){
                _error(ERR_MEM);
        }
        if (NULL==C11||NULL==C12||NULL==C21||NULL==C22||NULL==MM1||NULL==MM2) {
                _error(ERR_MEM);
        }
        for (i=0;i<m;i++) {
                A12[i]=(float *)malloc(m*sizeof(float));
                A21[i]=(float *)malloc(m*sizeof(float));
                B12[i]=(float *)malloc(m*sizeof(float));
                B21[i]=(float *)malloc(m*sizeof(float));
                C11[i]=(float *)malloc(m*sizeof(float));
                C12[i]=(float *)malloc(m*sizeof(float));
                C21[i]=(float *)malloc(m*sizeof(float));
                C22[i]=(float *)malloc(m*sizeof(float));
                MM1[i]=(float *)malloc(m*sizeof(float));
                MM2[i]=(float *)malloc(m*sizeof(float));
                if (NULL==A12[i]||NULL==A21[i]||NULL==B12[i]||NULL==B21[i]||NULL==C11[i]||NULL==C12[i]||NULL==C21[i]||NULL==C22[i]||NULL==MM1[i]||NULL==MM2[i]) {
                        _error(ERR_MEM);
                }
      }

  //省略计算各矩阵的步骤
  // 分线程再次调用STRASSEN, 传入的参数thread[i]中包含了float **A,**B,**C,分别也是一个动态分配的二位数组
    for (i = 0; i < 7; i++) {
      pthread_t id;
      if(pthread_create(&id,NULL,(void*)STRASSEN,(void*)&thread[i])) {
        perror("pthread_create");
        exit(1);
      }
      pthread_join(id,NULL);
    }

//省略一些


    for (i=0;i<m;i++) {
        free(A12[i]);
        free(A21[i]);
        free(B12[i]);
        free(B21[i]);
        free(C11[i]);
        free(C12[i]);
        free(C21[i]);
        free(C22[i]);
        free(MM1[i]);
        free(MM2[i]);
    }
    free(A12),free(A21),free(B12),free(B21);
    free(C11),free(C12),free(C21),free(C22),free(MM1),free(MM2);
    }
}


17 个解决方案

#1


不清楚哎 等高手来吧还是

#2


Segmentation   fault——段错误
解释:A segmentation fault (often shortened to segfault) is a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (e.g., attempts to write to a read-only location, or to overwrite part of the operating system). Systems based on processors like the Motorola 68000 tend to refer to these events as Address or Bus errors.

Segmentation is one approach to memory management and protection in the operating system. It has been superseded by paging for most purposes, but much of the terminology of segmentation is still used, "segmentation fault" being an example. Some operating systems still have segmentation at some logical level although paging is used as the main memory management policy.

On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.

翻译为:
所谓的段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。一旦一个程序发生了越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了

楼主参考。

#3


段错误一般为指针错误,你可以使用GDB模式调试,当程序崩溃后使用bt,看下在什么地方出的问题。

#4


程序本身应该是没有问题的,因为若使用静态数组的话,一切正常。 
  这个不一定,因为某些内存泄露和越界是程序运行中无法发现的,所以可能的问题还是程序的问题
还是要通过分析程序及利用调试工具来发现程序中的错误

#5


如果用gdb调试的话,可以看出段错误发生在哪一行代码上

#6



int get_mem_for_data(int x, int y, double*** data)
{
if(NULL == (*data = (double**)malloc(x*sizeof(double*))))return (-1);
for(int i = 0; i < x; i++)
(*data)[i] = (double*)malloc(y*sizeof(double));
static int k = 0;
printf("%d\n", k++);
return (0);
}

int main(int argc, char* argv[])
{
printf("Hello World!\n");
double** data[1000];
for(int i = 0; i < 1000; i++)
get_mem_for_data(100, 100, &data[i]);
data[999][99][99] = 1.0;
printf("%f\n", data[999][99][99]);
//释放内存你,略。
return 0;
}
调用了999次,也没问题啊?

#7


malloc可能分配内存失败,楼主考虑了么??

#8


既然静态数组可行,malloc肯定没问题

段错误一般来说 就是指针操作错误,要么释放了无效指针,要么是对无效指针进行操作,再要么是越界

建议你gdb 单步调试走一遍,问题可能不在这个函数里面

#9


用realloc()重新分配

#10


应该是内存操作的问题,也就是指针。

或者是内存分配错误。

希望可以帮到你!

#11


访问的地址越界了才会出现段错误的,可以在用gcc编译的时候加 -g 选项(记得在终端上开启生成core文件,即ulimit -c unlimited),然后再用gdb查看是哪条语句导致的错误

#12


谢谢大家的指点,
我发现了问题所在,确实不关malloc的事。
当我自己手动输入的时候,程序没有问题,
但当使用 $programe < input.dat
这样的命令时,就出现那个错误,这个是为什么呢?
我的接收输入的部分是这样的:

  for(i=0;i<size;i++) {
  for(j=0;j<size;j++) {
  fscanf(stdin,"%f",&args.A[i][j]);
  }
  }

  for(i=0;i<size;i++) {
  for(j=0;j<size;j++) {
  fscanf(stdin,"%f",&args.B[i][j]);
  }
  }


#13


programe < input.dat 你想将程序输出写到input里面么?按照你上面说的,怎么手动输入,不懂你的意思

#14


引用 13 楼 namelij 的回复:
programe < input.dat 你想将程序输出写到input里面么?按照你上面说的,怎么手动输入,不懂你的意思


不好意思 我弄错了

跟重定向没有关系 

还是内存的问题

因为当我尝试4*4的大小的时候,是可以的
但是8*8大小 就出现segmentation fault错误了

不知道为什么?  只能分配这么一点内存么?

#15


A[i][j] 检查一下,下标有没有越界?

#16


不是A的问题,还是malloc的问题,
因为segmentation fault错误是发生在  
A12=(float   **)malloc(m*sizeof(float   *)); 



引用 15 楼 keiy 的回复:
A[i][j] 检查一下,下标有没有越界?

#17


有结果了吗???

#1


不清楚哎 等高手来吧还是

#2


Segmentation   fault——段错误
解释:A segmentation fault (often shortened to segfault) is a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (e.g., attempts to write to a read-only location, or to overwrite part of the operating system). Systems based on processors like the Motorola 68000 tend to refer to these events as Address or Bus errors.

Segmentation is one approach to memory management and protection in the operating system. It has been superseded by paging for most purposes, but much of the terminology of segmentation is still used, "segmentation fault" being an example. Some operating systems still have segmentation at some logical level although paging is used as the main memory management policy.

On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.

翻译为:
所谓的段错误就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表,后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。一旦一个程序发生了越界访问,cpu就会产生相应的异常保护,于是segmentation fault就出现了

楼主参考。

#3


段错误一般为指针错误,你可以使用GDB模式调试,当程序崩溃后使用bt,看下在什么地方出的问题。

#4


程序本身应该是没有问题的,因为若使用静态数组的话,一切正常。 
  这个不一定,因为某些内存泄露和越界是程序运行中无法发现的,所以可能的问题还是程序的问题
还是要通过分析程序及利用调试工具来发现程序中的错误

#5


如果用gdb调试的话,可以看出段错误发生在哪一行代码上

#6



int get_mem_for_data(int x, int y, double*** data)
{
if(NULL == (*data = (double**)malloc(x*sizeof(double*))))return (-1);
for(int i = 0; i < x; i++)
(*data)[i] = (double*)malloc(y*sizeof(double));
static int k = 0;
printf("%d\n", k++);
return (0);
}

int main(int argc, char* argv[])
{
printf("Hello World!\n");
double** data[1000];
for(int i = 0; i < 1000; i++)
get_mem_for_data(100, 100, &data[i]);
data[999][99][99] = 1.0;
printf("%f\n", data[999][99][99]);
//释放内存你,略。
return 0;
}
调用了999次,也没问题啊?

#7


malloc可能分配内存失败,楼主考虑了么??

#8


既然静态数组可行,malloc肯定没问题

段错误一般来说 就是指针操作错误,要么释放了无效指针,要么是对无效指针进行操作,再要么是越界

建议你gdb 单步调试走一遍,问题可能不在这个函数里面

#9


用realloc()重新分配

#10


应该是内存操作的问题,也就是指针。

或者是内存分配错误。

希望可以帮到你!

#11


访问的地址越界了才会出现段错误的,可以在用gcc编译的时候加 -g 选项(记得在终端上开启生成core文件,即ulimit -c unlimited),然后再用gdb查看是哪条语句导致的错误

#12


谢谢大家的指点,
我发现了问题所在,确实不关malloc的事。
当我自己手动输入的时候,程序没有问题,
但当使用 $programe < input.dat
这样的命令时,就出现那个错误,这个是为什么呢?
我的接收输入的部分是这样的:

  for(i=0;i<size;i++) {
  for(j=0;j<size;j++) {
  fscanf(stdin,"%f",&args.A[i][j]);
  }
  }

  for(i=0;i<size;i++) {
  for(j=0;j<size;j++) {
  fscanf(stdin,"%f",&args.B[i][j]);
  }
  }


#13


programe < input.dat 你想将程序输出写到input里面么?按照你上面说的,怎么手动输入,不懂你的意思

#14


引用 13 楼 namelij 的回复:
programe < input.dat 你想将程序输出写到input里面么?按照你上面说的,怎么手动输入,不懂你的意思


不好意思 我弄错了

跟重定向没有关系 

还是内存的问题

因为当我尝试4*4的大小的时候,是可以的
但是8*8大小 就出现segmentation fault错误了

不知道为什么?  只能分配这么一点内存么?

#15


A[i][j] 检查一下,下标有没有越界?

#16


不是A的问题,还是malloc的问题,
因为segmentation fault错误是发生在  
A12=(float   **)malloc(m*sizeof(float   *)); 



引用 15 楼 keiy 的回复:
A[i][j] 检查一下,下标有没有越界?

#17


有结果了吗???