C++ 使用向量加载 500MB 数据使用 5GB RAM

C++ loading 500MB of data with vector use 5GB of RAM

我正在编写用于对大块字符串(~ 2GB)进行排序的代码,并且我正在使用类似于桶排序的方法。我有大约 47000 个向量,每个向量平均有 ~100 个元素 (char*)。 (由于输入的原因,有些可能有很多元素,有些可能是空的)

我获取输入的代码是这样的:

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#define digitize(a) ((a>47 && a<58)*(a-48)+(a>96 && a<123)*(a-87)) //base 36 convert
int main(){
 int n = 0;
    scanf("%d\n", &n);

    vector<char *> buckets[46657]; // 36 *36 *36 = 46656




    for (int i = 0; i < n; i++) {
        char *temp = static_cast<char *>(calloc(255, sizeof(char)));
        scanf("%s\n", temp);
        int d1 = temp[0];
        int d2 = temp[1];
        int d3 = temp[2];

        int index = digitize(d1) * 1296 + digitize(d2) * 36 + digitize(d3); // 1296 = 36*36

        buckets[index].push_back(temp);

    }
}

digitize 实际上是一个 base 36 转换器。 (即 0:0、1:1 .... a:10、b:11、...、z:36)因为我的数据由数字和小写字符组成。

通过 运行 此代码在 500MB 数据集(随机生成)上的文件 ram 使用量超过 4GB 并接近 5GB。 (OS:Windows7 64 位,IDE:Jetbrains CLion,编译器:G++)

正常吗?我不明白为什么它只使用这些大量的 ram 来获取数据。我还通过添加另一个循环检查了输出,它们是正确的。所以没有无限循环或类似的东西。代码运行良好,但使用大量 RAM。

想知道为什么它会使用这么大的 RAM。

是什么让您认为您消耗了 5Gb?

你创建了一个 46657 的数组vector<char*>。每个向量平均有 100 char* 指向一个新分配的 255 字节的字符串。那至少是 sizeof(buckets)+46657*100*(sizeof(char*)+255) 字节。根据实施情况,这可能约为 1.2 Gb。向量可能保留一些 space 以用于更快的增长。但这不会从根本上改变我们的量级。

所有这些都很大,可能超出您的需要,但与您测量的 5Gb 相去甚远。但是你首先测量了什么?

您提供的内存消耗统计数据很可能在操作系统级别进行管理。它是执行代码的进程消耗的内存,不一定是代码消耗的代码。所有这些都依赖于实现,但通常标准库可能会从 OS 分配非常大的内存块,因为对 OS 的调用比用户 space 中的本地调用更昂贵。然后在每次 newmalloc 调用时将这个大块切成小块。就像批发商和零售商。

要知道你的代码消耗的内存,你需要做更精确的内存monitoring/profiling。例如,您可以使用 valgrind 或其他工具,具体取决于您的 OS。

避免泄漏

我们没有看到完整的代码,所以也不排除泄露的可能。由于您手动管理memroy,因此泄漏的风险更高。更不用说未经清理的扫描,它可能会超过分配的 255 个字符并损坏内存。

因此,更安全的方法可能是:

vector<string> buckets[46657]; 
...
for ...
    string temp; // let the string take care of its own memory
    getline(cin, temp);  
    ...

作为副作用,如果您有许多较小的字符串,您还可以从优化的内存管理中受益。