我正在尝试对一个数组进行排序,该数组的元素大小约为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);
答案 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
检查核心转储。
必须处理代表数字的大量 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。