通过读取文件创建 map<string,vector<string>> 时如何管理内存
Posted
技术标签:
【中文标题】通过读取文件创建 map<string,vector<string>> 时如何管理内存【英文标题】:How is memory managed when creating a map<string,vector<string> > by reading files 【发布时间】:2019-01-16 09:09:49 【问题描述】:我想知道当不同的文件存储在字符串向量映射中时如何管理内存。 我试图读取每个 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;
所以,我不明白为什么内存与文件大小相比如此之高。有没有更有效的方法来构建这种容器?
【问题讨论】:
与您的问题完全无关,但为什么字符串流strad
?为什么不直接使用vecFile[i]
?您甚至不需要 path
变量(如果您让 read_file
取而代之的是 const
引用,那么您确实应该这样做)。
Why is vector array doubled?的可能重复
std::vector<std::string> a = read_file(path); evaluations[strad.str()]=a;
这是一个副本,你可以移动它(实际上你使用移动插入代替)。
一摞纸在抽屉里不会占用太多空间,但要找到你想要的那张却非常慢。为有效定位而整理的一堆文件将占用更多空间。
A std::string
会有一些开销。文件中的很多行意味着很多 std::string
s 和更多开销。您应该可以通过使用 std::vector<char>
来减少一些开销,但我不太确定这是您想要做的事情。
【参考方案1】:
您的场景中有很多内存开销:
-
您将每个文件行存储为单独的
std::string
对象。每个这样的对象本身都会占用一些空间(在 64 位架构上通常为 24 或 32 个字节),但是,存储的字符串(行字符)仅在字符串很短且小/短字符串优化 (SSO) 时才存储在其中应用(通常是来自 C++11 的常见标准库实现)。如果行很长,字符串的空间是动态分配的,每次分配也会有一些额外的内存开销。
您将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 GB 的文件,您甚至可以使用 32 位索引。如果处理的文件中有很多行,这些差异可能很重要。
更新
这个问题高度相关:C++ Fast way to load large txt file in vector。
【讨论】:
我会尝试实施这些建议,如果可行,我会接受答案。如果您有一个示例,主要针对第 2 点)(我不确定第 1 点)会释放大量内存,因为我没有很多文件),那就太好了 @froz 第 1 点)也可能节省大量内存,可能比第 2 点要多得多)。我会将整个文件读入单个std::string
,在计算行数时用空字符替换换行符,然后使用该计数器为向量索引保留空间,最后再次传递并存储索引。这 2 个结构(带有文件内容的字符串和索引向量)将是 read_file
函数的结果。
@froz 顺便说一句,重要的不是文件数量,而是每个文件中的行数。以上是关于通过读取文件创建 map<string,vector<string>> 时如何管理内存的主要内容,如果未能解决你的问题,请参考以下文章