Как хранить большое количество текстовых данных в памяти? - PullRequest
3 голосов
/ 28 января 2010

Я работаю над синтаксическим анализатором и задаюсь вопросом, как эксперт управляет большим количеством текста / строки (> 100 МБ) для хранения в памяти? ожидается, что контент будет доступен все время в быстром темпе. bg: redhat / gcc / libc

один массив символов выходит за границы, вызывая ошибку сегментации ... любая идея или опыт приветствуется, чтобы поделиться / обсудить ...

Ответы [ 8 ]

9 голосов
/ 28 января 2010

mmap (2) файл в виртуальной машине, и просто используйте его.

4 голосов
/ 28 января 2010

«один массив символов выходит за границы, вызывая ошибку сегментации» - я думаю, что это неправильно. Ошибка сегментации вызвана доступом к защищенной памяти, а не выделением слишком большого чанка. В любом случае вы должны иметь возможность выделить до 2-3 ГБ на 32-разрядной машине и многое другое на 64-разрядной.

Вы можете использовать массив символов, но если вам нужен быстрый доступ, возможно, вам понадобится какая-то индексация поверх этого.

Не могли бы вы уточнить ваш вариант использования? Вы пытаетесь создать парсер для языка c? Почему вы ожидаете такой длинный ввод или вывод: ни источник, ни двоичные файлы обычно не такие большие.

3 голосов
/ 28 января 2010

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);
2 голосов
/ 28 января 2010

Это очень необычный синтаксический анализатор C, который требует, чтобы исходный текст (если это то, о чем вы говорите) был сохранен в памяти. Большинство синтаксических анализаторов поочередно считывают исходный токен и сразу же преобразуют его во некоторое внутреннее представление. И они, как правило, содержат представление только для одного исходного файла (плюс #include), который вряд ли будет размером до 100 МБ - возможно, у вас есть некоторые проблемы с дизайном здесь?

1 голос
/ 28 января 2010

Если вы размещаете массив> 100Mb char в стеке, вы, скорее всего, переполните стек. Хотя вы можете увеличить размер стека с помощью параметров компилятора / компоновщика, это не обязательно решит проблему, поскольку некоторые ОС ожидают приблизительно линейного доступа к страницам стека (Google "сторожевые страницы стека")

Вместо этого, если вы знаете размер во время компиляции, попробуйте выделить массив static char. Еще лучше, используйте malloc(). (Код, который вы опубликовали, объявляет массив, размер которого зависит от переменной a - это называется «массив переменной длины», который является расширением C99, которое поддерживают не все компиляторы. OTOH каждая реализация C позволяет вам вызывать malloc() динамически распределять память.)

1 голос
/ 28 января 2010

Такой большой объем данных лучше хранить как

  1. Глобальный массив, если данные будут постоянными.
  2. В куче (память выделяется динамически), если глобальные переменные не разрешены в вашем случае.

Но помните, что не храните его в стеке, чтобы не переполнить его и не вызвать другие проблемы.

Если вы спрашиваете о конкретных структурах данных, которые можно эффективно использовать для хранения / доступа к этим данным, тогда я предлагаю:

  1. Хеш-таблица
  2. Массив
  3. Список.
0 голосов
/ 28 января 2010

извините, если это новичок, ошибка сегментации выглядит следующим образом.

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

В этом случае файл представляет собой ежедневный файл, сгенерированный в структурном текстовом формате перед синтаксическим анализом (аналогично xml). сами данные, которые довольно статичны, Я хочу сделать его доступным как можно быстрее, поэтому предпочитаю хранить его в памяти после анализа

0 голосов
/ 28 января 2010

Вы можете сэкономить много места, сжимая токены при чтении их из исходного потока (предположительно, текстового файла). Устранение лишних пробелов и комментариев при чтении вводимого текста может снизить ваши требования к памяти до 50%.

Но мне любопытно, почему вам нужно хранить столько памяти сразу. Строковые литералы, идентификаторы и записи таблицы символов могут быть кэшированы на диск, когда вы находитесь в точке синтаксического анализа, которая делает их недоступными или выходящими за рамки.

...