我目前正在构建一个动态地使用向量类处理大量内存的代码。
代码正在构建带push_back
的向量,其中重要的是要注意向量是2维的,表示数据矩阵。根据具体情况,这个矩阵可能很小,或变得特别大。
例如,数据矩阵可以有很少的行,每行有1000列,或者它可以获得具有相同数量的列的1000行,其中包含双数据类型。显然,这很容易成为一个问题,因为1000x1000x8 = 8 000 000字节,因此在内存中代表8 MB。但是如何增加10倍的列数和10倍的行数呢? (这很容易发生在我的代码中)。
我通过将数据矩阵写入HDD来解决这个问题,但这种方法相当慢,因为我没有充分利用RAM。
我的问题:
如何使用vector< vector<double> >
构建由push_back
表示的矩阵,但前提是有足够的内存可以分配。
如果内存量不足,我将继续将数据导出到HDD中,释放分配的内存并开始循环。我不知道的是如何检查每个push_back
执行的内存是否可用。
修改 我应该注意到我正在使用运行Ubuntu的64位机器。我不太确定OS分页是如何运行的,但我实际上在做的是在存在电场和磁场的情况下进行粒子的数值计算。可能有1亿个粒子在1000多个时间步中移动,这是很多GB的数据。但是,有时我只运行几十万个粒子进行RAM测试,没有问题,加快了计算过程。我试图创建一些通用的解决方案,将检查是否有足够的RAM用于另一个计算,如果没有,则将它们移动到文件中。这些粒子可以添加到系统中或从中流出,所以基本上我不知道矩阵在任何给定时间有多大。这就是为什么我需要“好吧就够了,把这些数据移出这里,这样我就可以重新开始”了。
答案 0 :(得分:3)
几乎所有替代“我会在我的代码中将数据推送到磁盘”都比这更好。
那是因为操作系统本身(如果我们说的是合理的现代操作系统,如Windows NT系列和Unix的大多数变体,包括Linux和MacOS X)都有能力处理虚拟内存并交换到磁盘,它会以比你想象的更聪明的方式这样做。
此外(根据Tony D的评论),使用“内存映射文件”是比手动读取/写入文件更好的方法 - 这不会立即与std::vector
或其他标准集合一起使用,但是可能是比在您的应用程序中手动处理读/写文件更好的选择 - 您只需说“这是一个文件,请给我一个指向代表该文件的内存的指针”,并且您使用该指针就像文件一样被加载到内存中。操作系统将负责管理文件的哪些部分在任何给定时间实际存在于内存中,类似于在分配比系统中存在的内存更多的内存时进行交换。
然而,当然有限制(适用于“分配超过可用于您的应用程序的RAM和内存映射文件解决方案)。如果您使用的是32位计算机(或32位计算机)操作系统或32位应用程序),您的进程可用的最大内存量将介于2GB和4GB之间 - 具体取决于操作系统(具有32位应用程序的64位操作系统可能会给您近4GB,定期设置32位Windows总共大约2GB。所以如果你的阵列变得足够大,那么地址中就不会有“足够的位”来跟踪它。此时你需要拆分工作某种方式。或者去64位操作系统和应用程序(当然这里需要64位处理器),在这种情况下,内存大小限制为128或256TB(如果我的心理算法工作 - 65536 * 4GB)总计 - 这可能比几乎每个人都有磁盘空间,更不用说RAM了。
编辑:
根据您给出的数据进行一些数学计算:每个粒子具有X,Y,Z位置,速度和“其他两个属性”将占用double
中的6 * 8 = 48个字节,{4}为6 {4 = 24字节float
。
乘以100M,我们得到一组数据的4.8GB。时间1000次,产生4.8TB的数据。这是一个巨大的数额,即使你有非常大的内存。使用mememory映射文件并不能真正将所有这些数据同时保存在内存中。如果您的计算机具有相当大的内存容量(16GB左右),那么一次在内存中保留两组可能会有效。但是你仍然会产生大量需要在某个时刻存储的数据,这很可能会占用大部分时间。对于合理的现代(单个)硬盘,大约50-100MB / s的速度是合理的预期。它可以通过某些RAID配置进行改进,但即便如此,它仍然是每秒数百兆字节,而不是每秒几千兆字节。因此,以100MB / s存储1 TB(1000GB)需要10000次,或大约3个小时。 4.8TB 15小时。这只是存储数据,没有计算[虽然这可能是一个最小的部分]。即使我们将数据集除以10,我们也有一个多小时,除以50,我们在分钟范围内下降。
无论您使用何种方法,存储和检索此类大型数据集至少可以说是非常耗时的。内存映射文件在很多方面都是“最不好的”,因为它在过程中复制的数据少一些。但它仍然是“磁盘速度”,它将成为计算速度的主导因素。