Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从文件中读取4000000000行并保存到C中的数组中_C_Linux_Memory Management_Out Of Memory - Fatal编程技术网

从文件中读取4000000000行并保存到C中的数组中

从文件中读取4000000000行并保存到C中的数组中,c,linux,memory-management,out-of-memory,C,Linux,Memory Management,Out Of Memory,我需要从文件中读取4000000000行并将它们保存到数组中 但是Linux内核会因为内存不足而终止进程: tail /var/log/kern.log ... Out of memory: Kill process ... 代码 #包括 #包括 #包括 int main(){ /* *逐行读取文件并写入数组 */ 分配的整数行=128; int max_line_len=15; 字符**数组=(字符**)malloc(sizeof(字符*)*已分配的行); if(数组==NULL){ fp

我需要从文件中读取4000000000行并将它们保存到数组中

但是Linux内核会因为内存不足而终止进程:

tail /var/log/kern.log
... Out of memory: Kill process ...
代码
#包括
#包括
#包括
int main(){
/*
*逐行读取文件并写入数组
*/ 
分配的整数行=128;
int max_line_len=15;
字符**数组=(字符**)malloc(sizeof(字符*)*已分配的行);
if(数组==NULL){
fprintf(stderr,“内存不足(1)。\n”);
出口(1);
}
file=fopen(“file”、“r”);
if(file==NULL){
fprintf(stderr,“打开文件时出错。\n”);
出口(2);
}
int il;
对于(il=0;1;il++){
int j;
/*我们检查过我们的线路分配了吗*/
如果(il>=已分配的行){
int新尺寸;
/*加倍分配并重新分配*/
新大小=分配的行数*2;
数组=(char**)realloc(数组,sizeof(char*)*新的大小);
if(数组==NULL){
fprintf(stderr,“内存不足”。\n”);
出口(3);
}
已分配的行数=新的行数;
}
/*为下一行分配空间*/
数组[il]=malloc(最大线长度);
if(数组[il]==NULL)
{
fprintf(stderr,“内存不足(3)。\n”);
出口(4);
}
if(fgets(数组[il],最大行长度-1,文件)==NULL)
打破
/*在生产线的末端去除CR或LF*/
对于(j=strlen(数组[il])-1;j>=0&&(数组[il][j]='\n'| |数组[il][j]='\r');j--)
;
数组[il][j+1]='\0';
}
/*关闭登录文件*/
fclose(文件);
/*打印文件中的数据数组*/
对于(i=0;i
做这件事最合适、最有效的方法是什么?也许读第一块,完成它,然后读下一块,依此类推


这个问题的解决方案是什么?

假设从每行读取一个
字节,则需要29GB的内存


对于如此庞大的数据,加载尽可能少的数据是至关重要的,处理后会过度释放内存。否则会丢失内存。

显而易见的解决方案是分块处理输入。如果您能够做到这一点,那么还有一个额外的好处,即您可以在I/O进行时(在当前块上)进行计算(大多数操作系统都进行前瞻缓冲),与先读取所有数据,然后在一个块中处理数据相比,实际时间更短

(对于那些正在实现
排序
类型实用程序的人,我经常提到这一事实。对于真正的、人类可测量的加速,你应该将输入读入树中,而不是读入数组,然后对数组进行排序,因为存储速度慢,并且插入每个输入记录(行)直接进入树本质上允许您使用等待I/O对数据进行排序所花费的时间。它可能会占用稍多的CPU时间(取决于树的实现)与真正优秀的数组排序算法相比,人类通常不太关心这一点。我们主要关心的是在现实世界中花在等待上的时间。我们不喜欢等待。)


如果输入记录(行)是随机访问的,并且您使用的是64位体系结构,那么内存映射技术可能会使其成为可能。(如果您可以分块完成工作,请这样做;如果您不能,内存映射允许您在没有足够RAM的情况下进行处理。)

几年前,我写了一个简单的例子,介绍如何在64位Linux中使用文件支持的稀疏内存映射

在这种情况下,可以使用只读内存映射随机访问文本文件。请注意,在Linux中,应该使用where
aligned\u length
是文本文件的长度,四舍五入到sysconf(SC\u PAGESIZE)
的下一个倍数。这样的映射不使用交换(因此交换空间的大小并不限制映射的大小),但是如果内存太紧,内核可以并且将删除页面(并在需要时从文件本身重新读取)

第二个内存映射可用于存储每行开头的偏移量(在64位体系结构上,
size\t
足够大)。此映射应使用
mmap(NULL,offbufsize,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_NORESERVE,fd2,0)
,其中
offbufsize
sysconf(_SC_PAGESIZE)
的倍数,但至少与输入文件中的行数乘以
sizeof(size_t)

确定每行的开头是一个最好分块执行的操作(例如512×1024=524288字节)。也就是说,您应该首先设置第二个映射,在必要时使用
ftruncate()
mremap()
对其进行扩展,在上述块中使用低级I/O(unistd.h
read()
)读取第一个文件,以确定每行的开头

我个人在实践中也做过类似的事情。即使使用通用换行符支持(同时自动支持
\r\n
或CRLF、
\n\r
或LFCR、
\r
或CR以及
\n
或LF),您也只需要在用于存储从大型文本文件读取的块的数组中额外存储几个字节。由于初始过程是完全线性的,因此可以保证使用
posix\u-fadvise(fd,0,0,posix\u-FADV\u-NOREUSE)
posix\u-fadvise(fd,0,0,posix\u-fadvise\u顺序)

考虑到至少有几GB的RAM可用于缓冲(即使在小型的64位Linux/POSIX工作站上,这也是一种典型的情况),即使Linux内核分页功能不是“神奇的”,它仍然工作得出奇地好

我在Linux中看到的内存映射比可用内存映射大得多,导致性能不理想的最常见原因是忘记了
#include <stdio.h>
#include <string.h>
#include <stdlib.h>


int main() {

    /*
     * Read line by line from the file and write into the array
     */ 

    int lines_allocated = 128;
    int max_line_len = 15;

    char **array = (char **)malloc(sizeof(char*)*lines_allocated);
    if (array==NULL) {
        fprintf(stderr,"Out of memory (1).\n");
        exit(1);
    }

    file = fopen("file", "r");
    if (file == NULL) {
        fprintf(stderr,"Error opening file.\n");
        exit(2);
    }

    int il;
    for (il=0;1;il++) {
        int j;

        /* Have we gone over our line allocation? */
        if (il >= lines_allocated) {
            int new_size;

            /* Double our allocation and re-allocate */
            new_size = lines_allocated*2;
            array = (char **)realloc(array,sizeof(char*)*new_size);
            if (array==NULL){
                fprintf(stderr,"Out of memory.\n");
                exit(3);
            }
            lines_allocated = new_size;
        }

        /* Allocate space for the next line */
        array[il] = malloc(max_line_len);
        if (array[il]==NULL)
            {
            fprintf(stderr,"Out of memory (3).\n");
            exit(4);
            }
        if (fgets(array[il], max_line_len-1, file)==NULL)
            break;

        /* Get rid of CR or LF at end of line */
        for (j=strlen(array[il])-1;j>=0 && (array[il][j]=='\n' || array[il][j]=='\r');j--)
            ;

        array[il][j+1]='\0';
    }

    /* Close login file */
    fclose(file);

    /* Print the array of data from the file */
    for (i=0; i < il; i++)
        printf("%s\n", array[i]);

    return 0;
}