【问题标题】:allocating 3 dimensional vectors of size 10000 10000 3 in c++在 C++ 中分配大小为 10000 10000 3 的 3 维向量
【发布时间】:2019-01-10 21:54:32
【问题描述】:

我正在制作一个图片编辑程序,但我被困在分配内存中。 我不知道发生了什么。

好的..所以当我这样做时:

std::vector<unsigned char> h;
for (int a = 0; a < 10000 * 10000 * 3; a++) {
    h.push_back(0);
}

这很好(对不起,我不得不这样做),但是当我这样做时:

std::vector<std::vector<std::vector<unsigned char>>> h;
for (uint32_t a = 0; a < 10000; a++) {
  h.push_back({});
  for (uint32_t b = 0; b < 10000; b++) {
    h.at(a).push_back({});
    for (uint32_t c = 0; c < 3; c++) {
      h.at(a).at(b).push_back(0xff);
    }
  }
}

我的内存使用量激增,并且出现错误:Microsoft C++ 异常:std::bad_alloc at memory location 0x009CF51C

我正在使用 .bmp。

目前,代码处于测试模式,所以基本上是一团糟…… 我今年 15 岁,所以不要对我抱太大期望。

我正在寻找解决方案,但我发现的只是如何处理大整数等等......

如果你能给我可能的另一个解决方案,但我希望我的代码尽可能地对初学者友好。

【问题讨论】:

  • 我怀疑您的图像尺寸是 10000 x 10000,并且您想存储像素 RGB 值?您可以使用一些库(例如 opencv)来有效地做到这一点。使用嵌套向量根本不适合。
  • 您可能想要构建一个 64 位应用程序。对于 300MB 的图像,它很容易填充可用的地址空间(可能小于 2GB,大约 1.2GB 是连续的)。使用 64 位应用程序将消除这两个问题。
  • 问题可能是“向量通常比静态数组占用更多的空间,因为分配了更多的内存来处理未来的增长。” ref。因此,在第二种情况下,实际大小可能比第一种情况下已经很大的 10000*10000*3=300MB 向量大得多。我建议使用第一种情况和将 x,y 位置转换为矢量索引的函数:index = (y * width) + x.

标签: c++


【解决方案1】:

这是由于vector&lt;char&gt; 的开销。每个具有 3 个元素的此类对象不占用 3 个字节,但可能占用 4 个字节(由于重新分配策略),加上 3 个可能占用 3*8=24 字节的指针。总体而言,您的结构占用的内存是它可能拥有的内存的 9.3 倍。

如果你用数组替换内部向量,它将开始工作,因为数组没有这个开销:

std::vector<std::vector<std::array<unsigned char, 3>>> h;
for (uint32_t a = 0; a < 10000; a++) {
  h.emplace_back();
  for (uint32_t b = 0; b < 10000; b++) {
    h.at(a).emplace_back();
    for (auto &c : h.at(a).at(b)) {
      c = 0xff;
    }
  }
}

另一种选择是将较小的尺寸放在第一位。

【讨论】:

  • 这很容易大于 32 位应用程序中的可用地址空间。
  • @drescherjm 2019 年 Windows 上的 32 位应用程序?
  • 它可能仍然是默认值,具体取决于 ide。编辑:0x009CF51C 是 32 位。
  • 这是我第一次看到类似 ` for (auto &c : h.at(a).at(b)) { c = 0xff; }` 它说 auto &amp;c : H.at(a... 它没有合适的开始功能...... wut?
  • for (auto &amp;c : h.at(a).at(b)) { 是一个基于范围的 for 循环。在 2011 年标准 c++11 中添加:en.cppreference.com/w/cpp/language/range-for
【解决方案2】:

我的猜测是内存被常量vector重新分配严重碎片化,导致疯狂。对于这么大的数据,我建议简单地存储一个一维预分配向量:

std::vector h(10000 * 10000 * 3);

然后想出一个数组访问方案,它接受 X/Y 参数并将它们转换为一维数组中的索引,例如:

int get_index(int x, int y, int width) {
    return ((y * width) + x) * 3;
}

如果图像大小始终是固定的,您也可以使用std::array(参见multi-dimensional arrays),因为大小是在编译时定义的,它不会遇到与动态分配的向量相同的内存问题。

【讨论】:

    【解决方案3】:

    我不知道这是否会帮助您解决问题,但您可以尝试使用构造函数一开始就为 vec of vecs of vecs 分配内存。

    std::vector<std::vector<std::vector<unsigned char>>> h(10000, std::vector<std::vector<unsigned char>>(10000, std::vector<unsigned char>(3,0xff)));
    

    顺便说一句,你 15 岁就开始编写 C++ 了!我直到 20 多岁才开始学习计算机科学。这确实是一条非常有市场的职业道路,并且有很多智力刺激、具有挑战性的东西需要学习。祝你好运!

    【讨论】:

    • 在这种情况下,预分配不会有太大帮助。
    • @πάνταῥεῖ,为什么他的第一个例子有效,而不是第二个?但是,是的,您可能是对的,预分配在这里无济于事。某事物的向量向量将与某事物的向量一样连续,是吗?
    • @mannygover 不幸的是没有。每个vector 都包含一个指向其动态分配的数据存储的指针,因此外部vector 包含一个指向N 个连续vectors 的指针,但每个内部vectors 都有一个指针,它可能是其他一些内存块或者可能不在其他内部vectors拥有的其他街区附近。
    • 您应该注意,大多数 CPU 按页分配内存块(例如,最小大小为 1K)。如果您有三个维度,则分配的这些页面会产生很大的开销。
    猜你喜欢
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多