创建地图时如何管理内存<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;
}
所以,我不明白为什么内存与文件大小相比如此之高。有没有更高效的方法来构建这种容器?
您的场景内存开销很大:
- 您将每个文件行存储为一个单独的
std::string
对象。每个这样的对象本身占用一些 space(在 64 位体系结构上通常为 24 或 32 字节),但是,仅当字符串很短且 small/short 时,存储的字符串(行字符)才存储在其中应用字符串优化 (SSO)(通常由 C++11 中的通用标准库实现)。如果行很长,字符串的 space 是动态分配的,每次分配也会有一些额外的内存开销。
- 你
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 位索引。如果您在处理的文件中有很多行,这些差异可能很重要。
更新
这个问题高度相关:。
我想知道当不同的文件存储在字符串向量映射中时如何管理内存。 我尝试读取每个 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;
}
所以,我不明白为什么内存与文件大小相比如此之高。有没有更高效的方法来构建这种容器?
您的场景内存开销很大:
- 您将每个文件行存储为一个单独的
std::string
对象。每个这样的对象本身占用一些 space(在 64 位体系结构上通常为 24 或 32 字节),但是,仅当字符串很短且 small/short 时,存储的字符串(行字符)才存储在其中应用字符串优化 (SSO)(通常由 C++11 中的通用标准库实现)。如果行很长,字符串的 space 是动态分配的,每次分配也会有一些额外的内存开销。 - 你
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 位索引。如果您在处理的文件中有很多行,这些差异可能很重要。
更新
这个问题高度相关: