当我读取一个大小为17 MB的100万网址文件时,我的程序占用了163 MB的大小

时间:2018-06-04 09:57:41

标签: c++ file memory memory-management memory-leaks

我正在以下列方式阅读该文件。

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。 我做错了什么以及如何减少程序占用的内存?

1 个答案:

答案 0 :(得分:1)

假设您在开始循环之前知道了_urlCount值,那么保存内存的最简单方法是在开始循环之前保留向量的元素,使用以下行:

urlList.reserve(_urlCount);

这将节省大量内存的原因是因为矢量的任何实现都通过保留初始少量元素来工作,通常是第一次变为非空,然后每次push_back都会超过存储容量。向量它分配一个更大的缓冲区,其容量是旧容量的一些常量(有时这个常量是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个字符串预留空间时,您将获得向量主体的一个大缓冲区。给定字符串的大小,您仍然会有与URL字符串关联的1,000,000个较小的缓冲区,并且您可以通过不使用std :: string来节省大量空间,但这是另一个故事,并且在此答案中没有解决。