3

我正在研究交流解析器,想知道专家如何管理大量文本/字符串(> 100mb)以存储在内存中?预计内容将始终快速访问。bg:redhat/gcc/libc

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

4

8 回答 8

9

mmap(2) 虚拟机中的文件,然后使用它。

于 2010-01-28T00:23:17.267 回答
4

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

您可以使用 char 数组,但如果您想要快速访问,那么您可能需要在此基础上进行某种索引。

您能否进一步说明您的用例?您是否正在尝试为 c 语言创建解析器?为什么你期望有这么长的输入或输出:源代码和二进制文件通常都没有那么大。

于 2010-01-28T00:27:23.200 回答
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);
于 2010-01-28T16:28:37.583 回答
2

这是一个非常不寻常的 C 解析器,它需要将源文本(如果您正在谈论的话)保存在内存中。大多数解析器一次有效地读取源代码,然后立即将其转换为某种内部表示。而且它们通常只保存单个源文件(加上#includes)的表示,这不太可能像 100Mb 一样大 - 也许您在这里有一些设计问题?

于 2010-01-28T11:31:25.220 回答
1

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

  1. 如果数据将保持不变,则为全局数组。
  2. 如果在您的情况下不允许全局变量,则在堆中(动态分配的内存)。

但请注意不要将其存储在堆栈中,以免它可能溢出并导致其他问题。

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

  1. 哈希表
  2. 大批
  3. 列表。
于 2010-01-28T01:16:24.337 回答
1

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

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

于 2010-01-28T11:26:23.130 回答
0

您可以通过在从源流(可能是文本文件)读取令牌时压缩令牌来节省大量空间。在阅读输入文本时消除多余的空格和注释可以将内存需求减少多达 50%。

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

于 2010-01-28T00:40:09.100 回答
0

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

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

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

于 2010-01-28T01:29:53.470 回答