我正在尝试对一个数组进行排序,该数组的元素是从一个大小约为5GB、包含约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);
int*array=malloc(sizeof(int)arraysize);inttemp=malloc(sizeof(int)*arraysize);
通常,无论何时分配内存,都要检查分配是否成功:
int *array = NULL, *temp = NULL;
if (NULL == (array = malloc(sizeof(int)*arraysize)))
{
fprintf(stderr, "Out of memory allocating %d bytesn", sizeof(int)*arraysize);
abort();
}
if (NULL == (temp = malloc(sizeof(int)*arraysize)))
{
fprintf(stderr, "Out of memory allocating %d bytesn", sizeof(int)*arraysize);
abort();
}
然后,一种可能性是在磁盘上使用一个整数文件(也可以对该文件进行mmap())来实现mergesorting。
但我觉得奇怪的是,在堆上分配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 filen");
abort();
}
fo = fopen("INTEGER.dat", "w");
if (NULL == fo)
{
fprintf(stderr, "Cannot open output filen");
abort();
}
ft = fopen("TEMP.dat", "w");
if (NULL == ft)
{
fprintf(stderr, "Cannot open output filen");
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 errorn");
abort();
}
if (b != fwrite(buffer, sizeof(int), b, ft))
{
fprintf(stderr, "write errorn");
abort();
}
b = 0;
}
}
if (b)
{
if (b != fwrite(buffer, sizeof(int), b, fo))
{
fprintf(stderr, "write errorn");
abort();
}
if (b != fwrite(buffer, sizeof(int), b, ft))
{
fprintf(stderr, "write errorn");
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 outputn");
abort();
}
if (MAP_FAILED == (sort = mmap (0, arraysize*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)))
{
fprintf(stderr, "mmap errorn");
abort();
}
if (-1 == close (fd))
{
fprintf(stderr, "error closing output filen");
return 1;
}
do_sort(sort, temp, arraysize);
if (-1 == munmap (sort, arraysize*sizeof(int)))
{
fprintf(stderr, "error releasing mmap for %sn", "sort");
abort();
}
听起来你使用的是32位操作系统版本,或者至少是32位编译器,产生的ib 32位指针,以及最多4 GB的内存(甚至更少,取决于操作系统)。切换到64位操作系统并使用64位编译器进行编译。
32位操作系统的问题是,它根本无法为您的"幼稚"算法寻址足够的内存,该算法要求所有数据都在一个平面内存空间中。出于同样的原因,使用mmap也无济于事。如果你必须坚持32位模式,你必须使用文件合并排序。
首先,如果您的数据集这么大,我会使用数据库。然后,您可以免费获得此功能以及访问/插入/更新/删除数据的简单方法。
但是,要回答您的问题,并且您在分配内存时遇到问题,请尝试使用内存映射文件。如果在Linux或UNIX上,请参阅mmap。