巨大数据集中的内存优化

时间:2011-11-21 12:15:07

标签: c++

处理所有,我已经实现了一些功能,并且喜欢问一些基本的东西,因为我没有关于C ++的基本知识。我希望,你们都会好心地告诉我应该向你们学习什么是好方法。 (请,这不是一个功课,我没有任何专家围绕我问这个)

我做的是;我从文件中读取输入x,y,z,点数据(大约3GB数据集),然后为每个点计算一个单独的值并存储在向量(结果)中。然后,它将在下一个循环中使用。然后,该向量将不再被使用,我需要获取该内存,因为它包含大量数据集。我想我可以用两种方式做到这一点。 (1)通过初始化一个向量,然后通过擦除它(见代码-1)。 (2)通过分配动态内存然后再解除分配(参见代码-2)。我听说这种取消分配效率低下,因为取消分配会再次耗费内存或者我误解了。

Q1) 我想知道在内存和效率方面的优化方式是什么。

Q2) 另外,我想知道函数是否通过引用返回是一种提供输出的好方法。 (请看代码-3)

码-1

int main(){

    //read input data (my_data)

    vector<double) result;
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){

         // do some stuff and calculate a "double" value (say value)
         //using each point coordinate 

         result.push_back(value);

    // do some other stuff

    //loop over result and use each value for some other stuff
    for (int i=0; i<result.size(); i++){

        //do some stuff
    }

    //result will not be used anymore and thus erase data
    result.clear()

代码-2

int main(){

    //read input data

    vector<double) *result = new vector<double>;
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){

         // do some stuff and calculate a "double" value (say value)
         //using each point coordinate 

         result->push_back(value);

    // do some other stuff

    //loop over result and use each value for some other stuff
    for (int i=0; i<result->size(); i++){

        //do some stuff
    }

    //de-allocate memory
    delete result;
    result = 0;
}

code03

vector<Position3D>& vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment) const
{
  vector<Position3D> *points_at_grid_cutting = new vector<Position3D>;
  vector<Position3D>::iterator  point;

  for (point=begin(); point!=end(); point++) {

       //do some stuff         

  }
  return (*points_at_grid_cutting);
}

6 个答案:

答案 0 :(得分:2)

对于如此庞大的数据集,我会避免使用std容器并使用内存映射文件。

如果您更喜欢继续使用std :: vector,请使用vector::clear()vector::swap(std::vector())释放已分配的内存。

答案 1 :(得分:1)

erase释放用于向量的内存。它减小了大小而不是容量,所以向量仍然保留了所有那些双打的足够内存。

让内存再次可用的最佳方法就像你的代码-1,但让向量超出范围:

int main() {
    {
        vector<double> result;
        // populate result
        // use results for something
    }
    // do something else - the memory for the vector has been freed
}

如果不这样做,清除矢量并释放内存的惯用方法是:

vector<double>().swap(result);

这会创建一个空的临时向量,然后用result交换它的内容(所以result为空且容量小,而临时具有所有数据和大容量) 。最后,它会破坏临时的,带上大缓冲区。

关于code03:通过引用返回动态分配的对象并不是一种好的方式,因为它不会给调用者提供很多提醒,说明他们负责释放它。通常,最好的办法是按值返回局部变量:

vector<Position3D> ReturnLabel(VoxelGrid grid, int segment) const
{
  vector<Position3D> points_at_grid_cutting;
  // do whatever to populate the vector
  return points_at_grid_cutting;
}

原因是,如果调用者使用对此函数的调用作为其自己的向量的初始化,那么称为“命名返回值优化”的东西就会启动,并确保尽管您按值返回,但没有副本价值就是。

不实现NRVO的编译器是一个糟糕的编译器,并且可能会有各种其他令人惊讶的性能故障,但在某些情况下NRVO不适用 - 最重要的是当值被赋给变量时由调用者而不是在初始化中使用。有三个修复:

1)C ++ 11引入了移动语义,它基本上通过确保临时分配是廉价的来进行排序。

2)在C ++ 03中,调用者可以发挥称为“交换优化”的技巧。而不是:

vector<Position3D> foo;
// some other use of foo
foo = ReturnLabel();

写:

vector<Position3D> foo;
// some other use of foo
ReturnLabel().swap(foo);

3)您编写了一个具有更复杂签名的函数,例如通过非const引用获取vector并将值填入其中,或者将OutputIterator作为模板参数。后者还为调用者提供了更大的灵活性,因为他们不需要使用vector来存储结果,他们可以使用其他容器,甚至可以一次处理一个容器而不一次存储整个批次。 / p>

答案 2 :(得分:1)

您的代码看起来像第一个循环中的计算值仅在第二个循环中使用上下文不敏感。换句话说,一旦你在第一个循环中计算了double值,就可以立即对它进行操作,而不需要一次存储所有值。

如果是这种情况,你应该这样实现。不用担心大量的分配,存储或任何东西。更好的缓存性能。幸福。

答案 3 :(得分:0)

vector<double) result;
    for (vector<Position3D>::iterator it=my_data.begin(); it!=my_data.end(); it++){

         // do some stuff and calculate a "double" value (say value)
         //using each point coordinate 

         result.push_back(value);

如果“结果”向量最终会有数千个值,这将导致许多重新分配。最好是使用足够大的容量进行初始化来存储或使用保留功能:

vector<double) result (someSuitableNumber,0.0);

这将减少重新分配的次数,并可能进一步优化您的代码。

我也会写:vector<Position3D>& vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment) const

像这样:

void vector<Position3D>::ReturnLabel(VoxelGrid grid, int segment, vector<Position3D> & myVec_out) const //myVec_out is populated inside func

您想要返回引用是正确的,因为您要避免复制。

答案 4 :(得分:0)

`C ++中的析构函数不能失败,因此释放不会分配内存,因为内存不能用无投保证分配。

除了多次循环,如果你以集成的方式进行操作可能会更好,即不是加载整个数据集,而是减少整个数据集,只需逐个读取点,然后应用直接减少,即代替

load_my_data()
for_each (p : my_data)
    result.push_back(p)

for_each (p : result)
    reduction.push_back (reduce (p))

只做

file f ("file")
while (f)
    Point p = read_point (f)
    reduction.push_back (reduce (p))

如果您不需要存储这些缩减,只需按顺序输出

file f ("file")
while (f)
    Point p = read_point (f)
    cout << reduce (p)

答案 5 :(得分:-1)

code-1工作正常,与代码2几乎相同,没有主要优点或缺点。

code03别人应该回答这个问题,但我相信在这种情况下,指针和引用之间的差异是微不足道的,我确实更喜欢指针。

话虽如此,我认为你可能正在从错误的角度接近优化。你真的需要所有点来计算第一个循环中一个点的输出吗?或者你可以重写你的算法只读一个点,计算你在第一个循环中的值,然后立即按你想要的方式使用它?也许不是单点,而是批点。这可能会减少你的内存需要相当多的处理时间只会略微增加。