【问题标题】:Efficient memory allocation for large nested vectors大型嵌套向量的高效内存分配
【发布时间】:2012-08-17 11:44:56
【问题描述】:

我正在创建一个存储在嵌套向量中的巨大矩阵:

typedef vector<vector<pair<unsigned int, char>>> Matrix;

外部向量最终将包含约 400.000 个向量,每个向量最多包含约 220 对(大多数包含较少)。这需要大约 1GB 的 RAM,并且是这样完成的:

Matrix matrix;
for (unsigned int i = 0; i < rows; i++) {
    vector<pair<unsigned int, char>> row;
    for (unsigned int j = 0; j < cols; j++) {
        // ...calculations...
        row.push_back( pair<unsigned int, char>(x, y) );
    }
    matrix.push_back(row);
}

前 20% 的速度非常快,但外部向量增长得越大,整个过程的速度就越慢。我很确定可以进行一些优化,但我不是该领域的专家。有什么简单的技巧可以加快速度吗?还是我的尝试有什么重大错误?

【问题讨论】:

  • 你确定你有足够的内存来分配它们吗?也许您的操作系统正在使用交换文件...
  • 我猜如果你需要一个那么大的矩阵,这个矩阵将是一个稀疏矩阵。在这种情况下,您最好这样处理矩阵。见en.wikipedia.org/wiki/Sparse_matrix
  • @AlexanderChertov 是的,我确定有足够的内存。
  • @AlexanderChertov 如果他使用的是 c++11,那么增长约 400.000 个向量或约 400.000 个共享指针的向量是可比的。不过,在 c++03 中你是完全正确的。
  • @Niko 对此进行了扩展:当向量增长时,它首先分配一个新的内存块来包含所有内容,然后将它已经拥有的所有内容移动到新位置,然后释放旧内存块。在 c++03 中移动内容需要复制包含的对象(因此是内部向量的副本),在 c++11 中,内部对象只是被移动 - 并且移动向量非常快。

标签: c++ optimization memory-management


【解决方案1】:

最好只使用单个一维向量并在某些函数/类中包装行、列索引。这样可以保证整个矩阵的内存是连续的。

而不是使用push_back 预先分配整个矩阵:

std::vector<pair<unsigned int, char>> matrix(rows * cols);

【讨论】:

  • @Andrew 在这种情况下,没有它应该会更快
  • 谢谢。将这一切压缩到一个向量中需要对其他代码进行大量更改,但保留/预分配的东西似乎有效。一个后续问题:如果我做vector.reserve(10); 然后复制这个向量,这是否会导致内存被保留给 2 * 10 个元素?
  • @Niko,在大多数实现中它不会,因为内存将为副本独立分配。
  • 我不确定单向量解决方案在这里是否合适,因为他明确表示他的向量是参差不齐的,并且大多数行包含的条目明显少于最大值。
  • @James Kanze 如果每行中的元素数量不变(或很少改变),我可能仍会使用单个内存块以及指向每行的指针向量。
【解决方案2】:

我将从明显的优化开始。 如果您在开始填充值(或可用上限)之前知道行数,则只需提前保留空间。 push_back 大量值花费最多的时间是重新分配内存和复制已包含的值。

Matrix matrix(rows);
for(unsigned i = 0; i < rows; i++) {
    vector<pair<unsigned int, char>> row(cols);
    for(unsigned j; j < cols; j++) {
        row[j] = // value
    }
    matrix[i] = row;
}

【讨论】:

    【解决方案3】:

    使用 VS 2010 编译器,结果证明以下方法效果最好:

    Matrix matrix;
    matrix.reserve(rows);
    
    vector<pair<unsigned int, char>> row;
    row.reserve(cols);
    
    for (unsigned int i = 0; i < rows; i++) {
        for (unsigned int j = 0; j < cols; j++) {
            // ...calculations...
            row.push_back( pair<unsigned int, char>(x, y) );
        }
        matrix.push_back(row);
        row.clear();
    }
    

    与创建一个每次为“cols”条目分配内存的新向量相比,创建一个用于构建所有行的向量消耗的内存要少得多。不过不太清楚为什么会这样。

    但是,我接受 Andreas 的回答,因为这只是针对我的具体情况的解决方案,而他的回答提供了此类优化所需的一般信息。

    【讨论】:

      【解决方案4】:

      当外向量增长时,问题是大量的数据复制。考虑将您的 typedef 更改为

      typedef vector< shared_ptr< vector<pair<unsigned int, char>> > > Matrix;
      

      并在开始使用值填充它之前执行matrix.reserve(rows)

      【讨论】:

      • 你真的是建议他动态分配所有嵌套的vector吗?
      • 如果事先不知道外向量中的元素个数,是的,我会试试的。
      猜你喜欢
      • 2019-07-09
      • 2013-05-17
      • 2023-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      相关资源
      最近更新 更多