创建地图时如何管理内存<string,vector<string> > 通过读取文件

How is memory managed when creating a map<string,vector<string> > by reading files

我想知道当不同的文件存储在字符串向量映射中时如何管理内存。 我尝试读取每个 10 mo 的不同文件以将它们放入内存中,当我使用 KSySGuard 检查内存时,出现的内存是我文件内存的两倍多 (~70mo)。 我给你一个代码示例: 有一个函数 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. 您将每个文件行存储为一个单独的 std::string 对象。每个这样的对象本身占用一些 space(在 64 位体系结构上通常为 24 或 32 字节),但是,仅当字符串很短且 small/short 时,存储的字符串(行字符)才存储在其中应用字符串优化 (SSO)(通常由 C++11 中的通用标准库实现)。如果行很长,字符串的 space 是动态分配的,每次分配也会有一些额外的内存开销。
  2. push_back 这些 std::string 对象到一个 std::vector,这通常会以指数方式增加内部缓冲区的大小(例如当它 运行 超出space)。这就是为什么当你事先知道向量元素的数量时使用保留space(std::vector::reserve)。

这是这种 "comfortable" 方法的代价。可能有帮助的是将整个文件内容存储为单个 std::string,然后仅将 indexes/pointers 存储到单独的 array/vector 中各行的开头(尽管您不能将这些指针视为字符串因为它们不会以空字符结尾;或者,实际上,如果您用空字符替换换行符,则可以)。

在 C++17 中,您可以将行作为 std::string_view 的实例存储到单个 std::string 中存储的整个文件内容。

请注意 std::string_view 可能比 pointer/index 大。例如,对于 libstdc++ 和 x86_64,sizeof(std::string_view) 是 16 个字节,但 pointer/index 将占用 8 个字节。对于小于 4 GB 的文件,您甚至可以使用 32 位索引。如果您在处理的文件中有很多行,这些差异可能很重要。

更新

这个问题高度相关: