排序大数组时出现分段错误

时间:2012-12-01 22:09:16

标签: c segmentation-fault

我正在尝试对一个数组进行排序,该数组的元素大小约为5 GB,包含大约500000个数据元素。

数据大小为300.000.000后,由于分段错误,程序在排序过程中出错并终止。

我认为问题是由于分配给程序的内存空间不足而引起的。如何在我的C代码中更改它?

你可以帮我解决这个问题吗?谢谢。

int arraysize = atoi(argv[1]);
int* array    = malloc(sizeof(int)*arraysize);
int* temp     = malloc(sizeof(int)*arraysize);
int i;

FILE *fi;
char buffer[20];
fi = fopen("DATASET.dat", "r");

for(i=0; i<arraysize; i++){
  fgets(buffer, 20, fi);
  array[i] = atoi(buffer);
}

fclose(fi);

//function is called to perform the sorting
mergesort_array(array, arraysize, temp);

3 个答案:

答案 0 :(得分:1)

  

int * array = malloc(sizeof(int) arraysize);   int temp = malloc(sizeof(int)* arraysize);

通常,每当您分配内存时,请检查分配是否成功:

int *array = NULL, *temp = NULL;

if (NULL == (array = malloc(sizeof(int)*arraysize)))
{
    fprintf(stderr, "Out of memory allocating %d bytes\n", sizeof(int)*arraysize);
    abort();
}
if (NULL == (temp = malloc(sizeof(int)*arraysize)))
{
    fprintf(stderr, "Out of memory allocating %d bytes\n", sizeof(int)*arraysize);
    abort();
}

然后,有可能使用整数文件在磁盘上实现mergesorting (你也可以mmap()文件)。

但我发现奇怪的是,在堆上分配300000个整数 - 最多4.8兆字节,使用64位整数 - 会导致分配错误,所以我认为这是mergesort实现中的一些内容。也许与递归实现有关。

我首先使用完整的调试信息编译程序,然后使用gdb检查核心转储。

“简单”的malloc问题

必须处理代表数字的大量 ASCII字符串,您可以先将其转换为整数的文件。

FILE *fi, *fo, *ft;
char buffer[20];
int  array[4096], b = 0;

fi = fopen("DATASET.dat", "r");
if (NULL == fi)
{
    fprintf(stderr, "Cannot open input file\n");
    abort();
}
fo = fopen("INTEGER.dat", "w");
if (NULL == fo)
{
    fprintf(stderr, "Cannot open output file\n");
    abort();
}
ft = fopen("TEMP.dat", "w");
if (NULL == ft)
{
    fprintf(stderr, "Cannot open output file\n");
    abort();
}
for(i=0; i<arraysize; i++){
   fgets(buffer, 20, fi);
   array[b++] = atoi(buffer);
   if (4096 == b)
   {
       if (b != fwrite(buffer, sizeof(int), b, fo))
       {
           fprintf(stderr, "write error\n");
           abort();
       }
       if (b != fwrite(buffer, sizeof(int), b, ft))
       {
           fprintf(stderr, "write error\n");
           abort();
       }
       b = 0;
   }
}
if (b)
{
    if (b != fwrite(buffer, sizeof(int), b, fo))
    {
        fprintf(stderr, "write error\n");
        abort();
    }
    if (b != fwrite(buffer, sizeof(int), b, ft))
    {
        fprintf(stderr, "write error\n");
        abort();
    }
}
fclose(fi); fi = NULL;
fclose(fo); fo = NULL;
fclose(ft); ft = NULL;

现在你有一个INTEGER.dat文件,它由固定大小的整数组成。从各方面来看,它是内存中数组的文件副本。临时数组也是如此。

可以告诉系统将该文件视为内存中的数组。

int *sort = NULL;
int *temp = NULL;

// Temp is not shown -- identical treatment as sort

fd = open ("INTEGERS.dat", O_RDWR);
if (fd == -1)
{
    fprintf(stderr, "cannot reopen output\n");
    abort();
}
if (MAP_FAILED == (sort = mmap (0, arraysize*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)))
{
    fprintf(stderr, "mmap error\n");
    abort();
}
if (-1 == close (fd))
{
    fprintf(stderr, "error closing output file\n");
    return 1;
}

do_sort(sort, temp, arraysize);

if (-1 == munmap (sort, arraysize*sizeof(int)))
{
    fprintf(stderr, "error releasing mmap for %s\n", "sort");
    abort();
}

答案 1 :(得分:1)

听起来你正在使用32位操作系统版本,或至少32位编译器,导致ib 32位指针,最多4 gig内存(甚至更少,取决于操作系统)。切换到64位操作系统并使用64位编译器进行编译。

32位操作系统的问题是,它无法为你的“天真”算法寻找足够的内存,这需要所有数据都在一个平坦的内存空间中。出于同样的原因,使用mmap也无济于事。如果你必须坚持32位模式,你必须使用文件合并部分排序。

答案 2 :(得分:0)

首先,如果您的数据集很大,我会使用数据库。然后,您可以免费获得此项以及访问/插入/更新/删除数据的简单方法。

但是,要回答您的问题并且您在分配内存时遇到问题,请尝试使用内存映射文件。如果在Linux或UNIX上,请参阅mmap