我应该如何在内存中存储大量文本数据?

时间:2010-01-28 00:20:17

标签: c performance memory io large-files

我正在研究一个c解析器并想知道专家如何管理大量的文本/字符串(> 100mb)来存储在内存中? 预计内容将以快节奏的方式随时访问。 bg:redhat / gcc / libc

单个字符数组将超出边界导致分段错误... 欢迎任何想法或经验分享/讨论......

8 个答案:

答案 0 :(得分:9)

mmap(2)VM中的文件,只需使用它。

答案 1 :(得分:4)

“单个字符串数组将超出边界导致分段错误” - 我认为这是不对的。通过访问受保护的内存而不是通过分配太大的块来引起分段错误。无论如何,你应该能够在32位机器上分配2-3GB,在64位机器上分配更多。

您可以使用char数组,但如果您想要快速访问,那么您可能需要某种索引。

您能否更多地澄清您的用例?您是否尝试为c语言创建解析器?为什么你期望有这么长的输入或输出:源和二进制都不常见。

答案 2 :(得分:3)

如果您想随机访问该数据,

mmap是处理存储在文件中的大量数据的最佳方式。

mmap告诉虚拟内存系统映射地址空间的连续部分以包含文件中找到的数据。虚拟内存系统将分配一系列地址空间,由该文件支持。当您访问该地址空间中的任何位置时,它将分配一页物理内存,从磁盘读取该文件的该部分,并将虚拟地址空间的该部分指向它用于读取文件的物理内存。当需要在物理内存中腾出更多空间时,它会写出对磁盘的任何更改(如果适用),并删除该部分虚拟地址空间的映射。

你会像这样使用它:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h> /* the header where mmap is defined */
#include <fcntl.h>

int file;
char *contents;
struct stat statbuf;
off_t len;

file = open("path/to/file", O_RDONLY);
if (file < 0)
  exit(1); /* or otherwise handle the error */

if (fstat(file, &statbuf) < 0)
  exit(1);

len = statbuf.st_size;

contents = mmap(0, len, PROT_READ, MAP_SHARED, file, 0);
if (contents == MAP_FAILED)
  exit(1);

// Now you can use contents as a pointer to the contents of the file

// When you're done, unmap and close the file.

munmap(contents, len);
close(file);

答案 3 :(得分:2)

这是一个非常不寻常的C语法分析器,它需要在内存中保存源文本(如果这就是你所说的)。大多数解析器一次有效地读取源代码并立即将其转换为某种内部表示。而且他们通常只保留一个源文件(加上#includes)的表示,这不太可能大到100Mb - 也许你在这里有一些设计问题?

答案 4 :(得分:1)

如此大量的数据最好存储为

  1. 如果数据将保持不变,则为全局数组。
  2. 在堆中(动态分配的内存),如果在你的情况下不允许全局变量。
  3. 但请注意不要将其存储在堆栈中,以免它溢出并导致其他问题。

    如果您询问可以有效用于存储/访问此数据的特定数据结构,那么我建议:

    1. 哈希表
    2. 数组
    3. 列表。

答案 5 :(得分:1)

如果您要分配&gt;堆栈上有100Mb char数组,你很可能会溢出堆栈。虽然您可以使用编译器/链接器选项增加堆栈大小,但这不一定能解决问题,因为某些操作系统期望对堆栈页面进行近似线性访问(谷歌“堆栈保护页面”)

相反,如果您在编译时知道大小,请尝试分配static char数组。更好的是,使用malloc()。 (您发布的代码声明了一个数组,其大小取决于变量a - 这称为“可变长度数组”,这是一个C99扩展,并非所有编译器都支持.OTOH每个C实现都允许您调用malloc()动态分配内存。)

答案 6 :(得分:0)

您可以通过压缩令牌来节省大量空间,因为您可以从源流中读取它们(可能是文本文件)。在阅读输入文本时消除多余的空格和注释可能会使内存需求降低多达50%。

但我很好奇为什么你需要立刻存储在内存中。字符串文字,标识符和符号表条目可以在您解析时使其无法访问或超出范围时缓存到磁盘。

答案 7 :(得分:0)

抱歉,如果是初学者pbm,会出现以下分段错误。

int a = 10000000; char content2[a]; content2[0] = 'a';

用例是,文件是在解析之前每天用结构纯文本格式生成的(类似于xml) 数据本身是非常静态的, 我希望尽可能快地访问它,所以我更喜欢在解析后将其保存在内存中