2015-12-30 2 views
0

Я реализую параллельный проект map/reduce. Однако, используя входной файл (более или менее) 1 ГБ, для примера слов с подсчетом слов, только с одним картографом (который отображает весь файл), я получаю исключение std::bad_alloc. К сожалению, это происходит только на удаленном Xeon Phi (с меньшей ОЗУ), поэтому нет глубокой отладки.Почему std :: bad_alloc выбрасывается?

Однако память занята в 2-х местах: когда картограф чтение (магазин) весь файл в char *:

void getNextKeyValue() { 
    key = pos;//int 
    value = new char[file_size];//file_size only with 1 mapper 
    ssize_t result = pread(fd, value, file_size, pos); 
    assert(result == (file_size)); 
    morePairs = false; 
} 

А другие, когда функция map называется и ряд pair<char*,int> хранится внутри vector в результате этой карты:

Карта функции:

std::function<void(int key, char *value,MapResult<int,char*,char*,int> *result)> map_func = [](int key,char *value,MapResult<int,char*,char*,int> *result) { 
    const char delimit[]=" \t\r\n\v\f"; 
    char *token , *save; 
    token = strtok_r(value, delimit, &save); 
    while (token != NULL){ 
     result->emit(token,1); 
     token = strtok_r (NULL,delimit, &save); 
    } 
}; 

emit реализации (и получение результатов на Картах):

void emit(char* key, int value) { 
     res.push_back(pair<char*,int>(key,value)); 
    } 
    ... 
    private: 
    vector<pair<char*,int>> res; 

Примечание: обычно key и value в emit шаблоно основе, но я опускаю их claricity в этом примере.

В первую очередь я думал, что std::bad_alloc был выброшен из-за char *value (который занимает 1 Гб), но было брошено исключение после тестирования cout сообщения, размещенного после value распределения (так that'not проблем).

Из того, что я прочитал о реализации strtok, изменен оригинал char* (добавление \0 в конце каждого токена), поэтому не добавляется дополнительная память.

Единственная оставшаяся возможность - это занятое пространство vector<pair<char*,int>>, но я не могу определить его пространство (пожалуйста, помогите мне об этом). Предполагая, что средняя длина слова составляет 5 символов, мы должны иметь ~ 2 * 10^8 слов.

UPDATE ПОСЛЕ 1201ProgramAlarm's answer: К сожалению, предвычисления количество слов, а затем вызвать resize() для того, чтобы исключить память не использованные вектора не представляется возможным по двум причинам:

  1. Это позволит значительно снизить производительность. Не вызывая emit и считая только слова файла размером 280 МБ, он занимает 1242 мс в течение общего времени выполнения 1329 мс (~ 5000 секунд, когда файл читается впервые).
  2. Используя это решение, конечный пользователь должен глубоко учитывать использование памяти, когда он записывает функцию карты, чего обычно не бывает в классических картах/сокращениях, таких как Hadoop.
+0

Пробовал ли вы использовать отладчик, чтобы увидеть, где вызывается исключение? –

+0

Как я уже сказал в вопросе, я не могу отлаживать, так как я запускаю программу на удаленном Xeon Phi. – justHelloWorld

ответ

0

Проблема не в пространстве, используемом vector, это все пространство, ранее использовавшееся вектором, когда его емкость была меньше. Если вы не назовете reserve на вектор, он начинает пуст и выделяет небольшое пространство (обычно достаточно большое для одного элемента), когда вы нажимаете первый элемент. Во время последующих нажатий, если у него недостаточно свободного места, он будет выделять больше (1.5x или 2x текущего размера). Это означает, что вам требуется достаточно свободной памяти для меньшего размера и большего размера.Поскольку освобожденные фрагменты памяти, когда они объединены, по-прежнему будут недостаточными для следующего большего количества запросов, может быть много свободной, но неиспользуемой памяти.

Вы должны позвонить по телефону res.reserve(/*appropriate large size*/) или перевести контейнеры в deque, что, в конце концов, потребуется больше места, не нужно будет перераспределять его по мере его роста. Чтобы получить размер для резервирования, вы можете один раз просмотреть свой файл, чтобы узнать, сколько слов действительно в нем, зарезервировать место для них, затем снова пройти его и сохранить слова.

+0

Ответил на вопрос обновления – justHelloWorld