在C++程序中使用巨大的矢量进行冻结

Freeze in C++ program using huge vector

本文关键字:冻结 巨大 程序 C++      更新时间:2023-10-16

我的C++程序有问题。我认为这是记忆力的问题。在我的程序中,我习惯于创建一些巨大的std::vector(我使用reserve来分配一些内存)。向量大小为1000 000,这是可以的,但如果我增加这个数字(大约1000万),我的程序将冻结我的电脑,我只能等待崩溃(或者如果幸运的话,程序结束)。我的向量包含一个叫做点的结构,它包含一个双向量。

我用valgrind检查是否有记忆力不足。但没有。根据它的说法,没有问题。也许不建议使用对象向量?或者可能有一些系统参数需要检查或其他什么?或者简单地说,矢量对计算机来说太大了?

你对此怎么看?

免责声明

请注意,这个答案假设了关于您的机器的一些事情;确切的内存使用情况和潜在的错误取决于您的环境。当然,当你不计算2d点时,崩溃会更容易,但例如4d点,这在计算机图形学中很常见,或者更大的点用于其他数字目的。

关于你的问题

这是相当多的内存分配:

#include <iostream>
#include <vector>
struct Point {
    std::vector<double> coords;
};
int main () {
    std::cout << sizeof(Point) << std::endl;
}

这将打印12,它是空Point的字节大小。如果您有2维点,请为每个元素添加另一个2*sizeof(double)=8,即现在每个Point总共有20个字节。

对于1000万个元素,您请求200万个字节的数据,例如对于2000万个元素来说,您请求4亿个字节。虽然这不会超过std::vector的最大索引,但操作系统可能没有那么多可用的连续内存。

此外,vector的内存需要经常复制才能增长。例如,当您push_back时就会发生这种情况,因此当您已经有一个400MiB的vector时,在下一个push_back时,您可能会有旧版本的vector,再加上新分配的400MiB*X内存,因此您可能很容易超过1000MiB的临时内存,等等。

优化(高级;首选

您是否需要始终存储数据?你能使用一种不需要那么多存储的类似算法吗?你能重构你的代码以减少存储空间吗?当你知道需要一段时间才能再次需要数据时,你能把一些数据核心化吗?

优化(低级别)

如果在创建外部向量之前知道元素的数量,请使用std::vector构造函数,它可以告诉您初始大小:

vector<Foo> foo(12) // initialize have 12 elements

当然,你可以优化很多内存;例如,如果你知道你总是只有2d点,那么只需要有两个double作为成员:20字节->16字节。当您并不真正需要double的精度时,请使用float:16字节->8字节。这是对$2/5$的优化:

// struct Point { std::vector<double> coords; };   <-- old
struct Point { float x, y; }; // <-- new

如果这仍然不够,则ad-hoc解决方案可以是std::deque,或者另一个非连续容器:无临时存储器";加倍";因为不需要调整大小;操作系统也不需要为您找到这样的连续内存块。

您还可以使用压缩机制、索引数据或固定点号。但这取决于你的具体情况。

struct Point { signed char x, y; }; // <-- or even this? examine a proper type
struct Point { short x_index, y_index; };

在没有看到您的代码的情况下,这只是猜测,但我怀疑这在很大程度上是由于您试图分配大量连续的内存。std::vector保证在连续内存中,因此如果您试图分配大量空间,操作系统必须尝试找到一块可以使用的大内存。对于2MB来说,这可能不是问题,但如果您突然尝试分配200MB或2GB的连续内存。。。

此外,每当您向向量中添加新元素并强制调整其大小时,所有现有元素都必须复制到分配的新空间中。如果您有900万个元素,并且添加9000001元素需要调整大小,则必须移动900万个图元。矢量越大,复制时间就越长。

请尝试使用std::deque。它基本上会分配页面(将是连续的),但每个页面都可以分配到任何合适的位置。