【发布时间】:2021-10-21 07:52:54
【问题描述】:
我在使用大型多维 std::vector 变量时观察到意外行为。特别是,当我分配一个大尺寸的 4 维向量时,使用内存分析器可以看出,我的任务很快就会使用比变量所需更多的内存。
重现此行为的 MWE 如下:
#include <vector>
#include <iostream>
int main(int argc, char *argv[]){
getchar();
std::vector<std::vector<std::vector<std::vector<int64_t>>>> F(1, std::vector<std::vector<std::vector<int64_t>>>(15, std::vector<std::vector<int64_t>>(256, std::vector<int64_t>(100000, 0))));
getchar();
}
下图显示了任务使用的内存。阵列的大小大约需要 3GB,但内存使用量很快就会超过 6GB。请注意,向量的最后一个维度是最大的,这意味着向量类的内存开销相对较小。
这已在 64 位系统上的 Manjaro 下观察到,使用 g++(gcc 版本 11.1.0 (GCC))编译。我用psrecord记录内存使用情况。有趣的是,我无法为低维向量重现相同的行为。即使我只删除第一个维度(大小为 1),我也无法在我的系统上重现此过冲。
有谁知道这是从哪里来的,或者是否可以避免(不使用大的一维向量)?这样做的主要问题是我的操作接近系统提供的最大内存,这意味着短暂的过冲会导致内存交换。
我会很高兴有任何想法和 cmets。提前致谢。
【问题讨论】:
-
这种调试问题比软件工程更适合Stack Overflow。提示:
std::vector::vector(size_t n, const T& value)获取值的引用并将其复制到每个元素中。外部构造函数称为vector(1, 3gb_data_structure)。由于制作了副本,因此 2 倍的预期内存使用量听起来是正确的。 -
向量的向量的向量真的是最好的数据结构吗?将至少一些维度放入一维缓冲区是相当常见的,并使用一些自定义索引来提供多维索引。
-
@amon 感谢您的 cmets!我会在以后的帖子中记住关于适用性的评论,谢谢!这听起来确实很有道理。我假设有某种向量或编译器优化可以避免这种复制更小的尺寸,否则我不明白为什么这只发生在 4 维的情况下。
-
std::vector<std::vector<std::vector<int64_t>>>(1, std::vector<std::vector<int64_t>>(256, std::vector<int64_t>(100000, 0)))使对象大小为 3GB。然后将其复制到F,因此F的大小也是 3GB,总共消耗 6GB。该行结束后,临时对象被销毁,然后您降回到仅消耗 3GB 的空间。恕我直言,解决方案是使用一维向量。这并不意味着您不能将其包装在一个伪造它具有多个维度的类中,如下所示:stackoverflow.com/a/43358434/4342498 -
@Yksisarvinen 是的。
vector不能在这里使用&&,因为它会将值的N复制到向量中。如果它移动了,您只能制作 1 个对象,而不是N。