c++ - 为什么 unordered_set 使用的内存比它包含的数据多得多?

标签 c++ c++11 unordered-set

我有一个相对较大的文件,我需要确保只包含唯一的行。该文件只有 500MB。我知道有很多开销,但我看到了将近 5GB 的 RAM 使用率。我本可以使用外部合并排序并保持少量 RAM 来完成此操作,但这似乎可以更快地编写代码。

我正在使用 VC++14。

#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <unordered_set>

using std::vector;
using std::string;
using std::unordered_set;

class uniqify {
    unordered_set<string> s;
public:
    auto exists(const string &filename) const -> bool {
        std::ifstream fin(filename);
        bool good = fin.good();
        return fin.close(), good;
    }

    void read(const string &filename) {
        std::ifstream input(filename);
        string line;
        while (std::getline(input, line))
            if (line.size())
                s.insert(line);
    }

    void write(const string &filename) const {
        std::ofstream fout(filename);
        for (auto line : s)
            fout << line << "\n";
        fout.close();
    }
};

int main(int argc, char **argv) {
    uniqify u;
    string file("file.txt");
    if(u.exists(file))
        u.read(file);
    u.write("output_file.txt");
    return 0;
}

是什么导致 RAM 飙升 10 倍以上?

最佳答案

unordered_set 是一个基于节点的容器。上次我检查时,MSVC 使用双向链表存储元素,并将迭代器 vector 放入该链表中以描述存储桶。 unordered_set 的默认 max_load_factor() 为 1,因此至少有多个桶作为节点。它在每个桶中存储了大约一个 list 迭代器——这是一个指针。因此,对于每个节点,您有来自双向链表的两个指针的开销,加上至少一个来自桶的指针,总共三个指针。

然后 std::string 在上面添加它自己的开销。我相信 MSVC 的 std::string 是两个指针 + 16 个字节 SSO buffer .超过 15 个字符的字符串将使用动态分配,这会花费更多。

因此集合中的每个字符串至少需要 5 个指针 + 16 个字节的 SSO 缓冲区,每个指针 8 个字节,即每个字符串最少 56 个字节。有 5500 万个字符串,大约有 3GB。我们没有计算超过 15 个字符的字符串,也没有计算每个节点的内存分配开销,这很容易达到 5GB。

关于c++ - 为什么 unordered_set 使用的内存比它包含的数据多得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37177163/

相关文章:

c++ - XCode std::thread C++

c++ - 为什么表达式的结果取决于表达式的放置位置?

c++ - 传递 std::function<bool(std::string)> &&callback(即作为右值 move )是否安全,效果如何?

c++ - 如何将 emplace 用于将 shared_ptr 保存到对象的 unordered_set?

c++ - boost::unordered_map -- 需要指定自定义哈希函数来散列 std::set<int> 吗?

c++ - 为模板化类创建类型别名

c++ - 在C++中声明一个较大的全局变量会导致错误消息0xc0000018

c++ - 使用 std::Optional<A> 作为 A 类的类成员

c++ - boost 或 C++0x 中的任何 RAII 模板

c++ - STL 无序容器的局部迭代器有哪些用途?