【问题标题】:Modify malloc strategy for 2D Array so malloc succeeds修改二维数组的 malloc 策略,使 malloc 成功
【发布时间】:2010-02-06 14:09:32
【问题描述】:

我们最近收到一份报告,称我们的应用程序有时会无法运行。我追踪到了问题代码:

struct ARRAY2D
{
   long[] col;
}

int numRows = 800000;
int numCols = 300;
array = (ARRAY2D*) malloc(numRows * numCols * sizeof(long))

如果用户没有足够大的空闲块,则此 800 Mb 分配可能会失败。更改内存分配方式的最佳方法是什么?

请记住,我有大量代码可以像这样访问这个对象:array[row].col[colNum],所以我需要一些需要次要或主要查找和替换的东西数组访问代码的编辑。

【问题讨论】:

  • 您使用的是 C 还是 C++?你的标签没有帮助。
  • @Poita:他可能在使用 C++,但只使用了 C 特性。 耸耸肩
  • 您的应用是否总是需要分配此内存,还是取决于应用中的特定场景?
  • 我总是要分配这么多内存。
  • C++ 是否允许您声明像 long[] a 这样的数组而不是 long a[]?我在标记为 C 或 C++ 的问题中多次看到这种类型的语法。还是人们只是不复制和粘贴他们的代码?

标签: c++ c malloc


【解决方案1】:

你的ARRAY2D会不会有很多默认值?如果是,您需要一个稀疏数组。 最小的改变是使用unordered_map(或hash_mapmap):

static const int numRows = 800000;
static const int numCols = 300;

struct ARRAY2D {
  long col[numCols];
  // initialize a column to zero; not necessary.
  ARRAY2D() { memset(col, 0, sizeof(col)); }
};


// no need to malloc
std::unordered_map<int, ARRAY2D> array;
...
// accessing is same as before ...
array[1204].col[212] = 4423;
printf("%d", array[1204].col[115]);
...
// no need to free.

如果行索引始终是连续的但远小于numRows,请改用std::vector

std::vector<ARRAY2D> array;
...
// resize to the approach value.
array.resize(2000);
...
// accessing is same as before ...
array[1204].col[212] = 4423;
printf("%d", array[1204].col[115]);
...
// no need to free.

【讨论】:

  • 数组的某些部分会有默认值。有时行数少于 numRows,列数少于 numCols。
  • OP 已标记为 C 和 C++,所以我假设他也在寻找可用于 C 的解决方案
  • @Brian:行数和列数少于最大值是可以的,因为无序映射只有在条目数增加时才会使用更多内存。
  • @Andreas Bonini 大概表示他只使用 C 功能,C 标准库的元素。
  • 如果 STL 是最好的选择,那么我可以使用它。
【解决方案2】:

您可以单独分配较小的内存块,而不是一个大块。

long** array = NULL;  
array = (long**) malloc(numCols * sizeof(long*));  
for (int i = 0; i < numCols; i++)  
   array[i] = (long*)  malloc(numRows * sizeof(long));

通常,memory allocation may fail,每次分配。但是,从统计上说,由于memory fragmentation,分配单个大内存块比分配 N 个小块更容易失败。 虽然,上面的解决方案也可能会导致问题,因为它有点像一把双刃剑,因为它可能会导致进一步的内存碎片。

换句话说,没有普遍完美的答案,解决方案取决于系统和应用程序的细节。

从 cmets 看来,C++ 库是一种可能性,然后基于std::vector(即generic vector of vectors in C++)或使用Boost.MultiArray的解决方案

【讨论】:

  • 我不确定我是否理解您的代码 sn-p。分配仍然会失败,对吧?
【解决方案3】:

我写了一个简单的例子,我将如何分配大块的数组:

#include <stdlib.h>
#include <stdio.h>

struct ARRAY2D {
  long *col;
  char free;
};

struct ARRAY2D *ARRAY2D_malloc( int numRows, int numCols ){
  struct ARRAY2D *rows = malloc( numRows * sizeof(struct ARRAY2D) );
  if( rows ){
    for( int i=0,b=numRows; i<numRows; i+=b ){
      char *mem;
      while( b && !(mem = malloc(b*numCols*sizeof(rows[0].col[0]))) ) b--;
      if( b<1 ){
        while( --i >= 0 ) if(rows[i].free) free(rows[i].col);
        free(rows); rows=NULL; break;
      }
      for( int j=i; j<i+b && j<numRows; j++ ){
        rows[j].free=(j==i);
        rows[j].col = (void*)mem; mem += numCols*sizeof(rows[0].col[0]);
      }
    }
  }
  return rows;
}

int main(void){
  int numRows = 8000000;
  int numCols = 300;
  struct ARRAY2D *array = ARRAY2D_malloc( numRows, numCols );
  if( array ){
    printf( "array[numRows-1].col[numCols-1]=%li\n", array[numRows-1].col[numCols-1]=3 );
  }
  else{
    puts("not enough memory");
  }
}

b 是一步分配的行数。当没有大块可用内存时,将b 递减 1 是一种简单的策略。

【讨论】:

    【解决方案4】:

    您的代码有语法错误:您缺少分号并且long[] col; 是无效的 C 或 C++。

    给定:

    struct ARRAY2D
    {
       long *col;
    };
    ARRAY2D *array;
    int numRows = 800000;
    int numCols = 300;
    array = (ARRAY2D*) malloc(numRows * numCols * sizeof(long));
    

    您可能分配了错误的内存量:sizeof(long) 应替换为 sizeof *arraysizeof(ARRAY2D)

    假设您的数量正确,您可以将array 索引为:array[i]i[0, numRows*numCols) 范围内。您还没有为任何array[i]col 成员分配任何内存,因此您不能索引到其中的任何col。因此,鉴于您发布的分配方案,您对 array[row].col[colNum] 的使用是错误的。

    如果您发布一些有效的真实代码,也许会有所帮助。

    【讨论】:

      猜你喜欢
      • 2011-10-30
      • 1970-01-01
      • 2013-11-30
      • 1970-01-01
      • 2018-03-20
      • 2014-06-25
      • 1970-01-01
      • 2016-08-09
      • 1970-01-01
      相关资源
      最近更新 更多