当我读取大小为 17 mb 的 100 万个 url 文件时,我的程序占用 163 mb
Posted
技术标签:
【中文标题】当我读取大小为 17 mb 的 100 万个 url 文件时,我的程序占用 163 mb【英文标题】:When I read a file of 1 million urls having size of 17 mb, my program occupies size of 163 mb 【发布时间】:2018-06-04 09:57:40 【问题描述】:我正在通过以下方式读取文件。
std::vector<std::string> urlList;
std::ifstream infile("top1m.txt");
std::string line;
std::cout << "Loading urls from file" << std::endl;
for (int offset = 0; offset < _urlCount; offset++) //_urlCount=1000000
std::getline(infile, line);
if (!line.empty())
if (line.back() == '\r')
line.erase(line.length() - 1, std::string::npos);
urlList.push_back(std::string("http://").append(line));
inflie.close();
top1m.txt 为 17 mb。 在阅读文件之前,我的 .exe 文件只有 6 mb。 我做错了什么,如何减少程序占用的内存?
【问题讨论】:
你如何检查你的进程使用了多少内存? 我在任务管理器里看到了。 @Someprogrammerdude 这与您的问题无关,但是当您想删除std::string
的最后一个字符时,只需说 line.pop_back();
就简单多了
1.众所周知,任务管理器对内存使用不可靠。 2. 如果没有其他程序在争夺资源,Windows 可能不会立即回收释放的内存。
任务管理器的Working set
列可能会引起有趣的阅读。它在Details
选项卡中可用(作为一个选项)。投票赞成(叹气)。这个问题有什么问题?
【参考方案1】:
鉴于您在开始循环之前知道 _urlCount 值,最简单的节省内存的方法是在开始循环之前保留向量的元素,使用以下行:
urlList.reserve(_urlCount);
这将节省大量内存的原因是因为任何 vector 的实现都是通过保留初始少量元素来工作的,通常是第一次变为非空时,然后每次 push_back 都会超过vector 它分配一个更大的缓冲区,其容量是旧容量的某个常数倍(有时这个常数是 2,但在实现之间会有所不同),然后它在添加新元素之前将现有元素从旧缓冲区复制到新缓冲区。旧的缓冲区通常留在内存中作为重用的候选对象。
因此,假设为原始大小选择的容量为 8 个元素,增长因子为 2,忽略 malloc 开销,但假设较小的缓冲区没有被重用,至少在您检查程序的大小。
当您有 1 个字符串时,第一个向量体可以容纳 8 个字符串。 当您有 8+1 个字符串时,新向量体的容量为 2*8,但您仍然拥有(作为释放的内存)用于容量为 8 的旧向量体的旧缓冲区。
当您拥有 1,000,000 个字符串时,您可能在内存中拥有以下缓冲区:
1 个用于向量体的缓冲区,可容纳 2 ** 20 个字符串
1 个空闲缓冲区,可容纳 2 ** 19 个字符串
1 个空闲缓冲区,可容纳 2 ** 18 个字符串
...
1 个空闲缓冲区,可容纳 8 个字符串
当然,其中一些较小的缓冲区有可能在某个时候被重用,我只是弥补了 8 的初始容量并使用了 2 的增长因子,因为我在 std:: 的一些旧实现中看到了它向量,我也忽略了关于 std::string 实现的细节,但你明白了。
当您预先为 1,000,000 个字符串预留空间时,您将只获得一个用于向量体的大缓冲区。考虑到字符串的大小,您仍将有 1,000,000 个与 URL 字符串关联的较小缓冲区,并且您可以通过不使用 std::string 来节省大量空间,但这是另一回事,此答案中未解决。
【讨论】:
以上是关于当我读取大小为 17 mb 的 100 万个 url 文件时,我的程序占用 163 mb的主要内容,如果未能解决你的问题,请参考以下文章