当我读取大小为 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的主要内容,如果未能解决你的问题,请参考以下文章

核心数据文件大小

文件大小适中的构建挂起

HDFS中的数据块大小,为啥是64MB?

S3 文件大小为十进制时的频谱表清单文件

尝试发送 100 MB 批处理时出现 Azure 服务总线错误

您需要将 APK 文件大小减少到 100MB 或使用 APK 扩展文件 [重复]