Как управляется память при создании карты <string, vector <string>> путем чтения файлов - PullRequest
0 голосов
/ 16 января 2019

Мне интересно, как управляется память, когда разные файлы хранятся в карте строковых векторов.Я пытался прочитать разные файлы по 10 месяцев каждый, чтобы поместить их в память, и когда я проверяю память с помощью KSySGuard, появляется больше, чем в два раза больше памяти моих файлов (~ 70 месяцев).Я даю вам пример кода для этого: есть функция readfile ():

std::vector<std::string> read_file(std::string& path){
    ifstream fichier(path);
    std::vector<std::string> fich;
    if(fichier){
       string ligne;
        while(getline(fichier, ligne)){
           fich.push_back(ligne);
        }
     }
    fichier.close();
    return fich;
}

Эта функция используется в другой, которая строит мою карту:

std::map<std::string, std::vector<std::string>> buildmap(std::string folder){
    std::map<std::string,std::vector<std::string>> evaluations; std::vector<std::string> vecFiles = {"file1","file2","file3"};
    for( auto i = 0; i < vecFiles.size(); i++ )
    {
        std::stringstream strad;
        strad <<vecFiles[i] ;
        std::string path(folder+vecFiles[i]);
        std::vector<std::string> a = read_file(path);
        evaluations[strad.str()]=a;
    }
    return evaluations;   
}

Итак, яНе понимаю, почему объем памяти такой большой по сравнению с размерами файлов.Есть ли более эффективный способ создания такого типа контейнера?

1 Ответ

0 голосов
/ 16 января 2019

В вашем сценарии много дополнительной памяти:

  1. Каждая строка файла сохраняется как отдельный объект std::string. Каждый такой объект занимает некоторое пространство (обычно 24 или 32 байта в 64-разрядной архитектуре), однако сохраненная строка (символы строки) хранится внутри него только тогда, когда строка является короткой, а оптимизация маленькой / короткой строки (SSO) применяется (обычно это обычные реализации стандартной библиотеки из C ++ 11). Если строки длинные, пространство для строки выделяется динамически, и каждое выделение также имеет дополнительные накладные расходы памяти.
  2. Вы push_back эти std::string объекты в std::vector, которые обычно увеличивают размер внутреннего буфера в геометрической прогрессии (например, удваивая его, когда ему не хватает места). Вот почему резервируемое пространство (std::vector::reserve) используется, когда вы заранее знаете количество векторных элементов.

Это цена за такой «удобный» подход. Что может помочь, так это сохранить все содержимое файла как один std::string, а затем сохранить только индексы / указатели на начало отдельных строк в отдельном массиве / векторе (хотя вы не сможете обрабатывать эти указатели как строки, так как они не будут завершается нулем, или, фактически, вы можете заменить символы новой строки на нулевые символы).

В C ++ 17 вы можете хранить строки как экземпляры std::string_view для всего содержимого файла, хранящегося в одном std::string.

Просто обратите внимание, что std::string_view, вероятно, будет больше, чем указатель / индекс. Например, для libstdc ++ и x86_64 sizeof(std::string_view) составляет 16 байтов, но указатель / индекс будет занимать 8 байтов. А для файлов размером менее 4 ГБ вы даже можете использовать 32-битные индексы. Если в обработанных файлах много строк, эти различия могут иметь значение.

UPDATE

Этот вопрос очень актуален: C ++ Быстрый способ загрузки большого текстового файла в векторе .

...