删除[]性能问题

时间:2011-01-29 14:20:15

标签: c++ arrays performance memory-management

我写了一个程序,它计算流水车间调度问题。

我需要帮助优化程序中最慢的部分:

首先是数组2D数组分配:

this->_perm = new Chromosome*[f];

//... for (...)

this->_perm[i] = new Chromosome[fM1];

它工作得很好,但是当我尝试删除数组时会出现问题:

delete [] _perm[i];

执行上面的行需要很长时间。 Chromosome是大约300k元素的数组 - 分配它只需不到一秒钟,但删除时间远远超过一分钟。

我很感激任何改进删除部分的建议。

4 个答案:

答案 0 :(得分:4)

检查你的析构函数。

如果你正在分配一个内置类型(例如一个int),那么分配300,000个它们将比相应的删除更昂贵。但这是一个相对术语,在一个块中分配的300k非常快。

当你分配300k染色体时,分配器必须分配300k *大小的Chromosome对象,正如你所说的那样快 - 我不能看到它做得那么多(即构造函数调用优化为虚无)

但是,当你来删除时,它不仅释放了所有内存,而且还为每个对象调用析构函数,如果它很慢,我猜想每个对象的析构函数都需要很小,但是很明显,当你有300k的时候。

答案 1 :(得分:4)

总的来说,你应该 永远不要在C ++中手动管理内存 。这将导致泄漏,双重删除和所有kinds of nasty inconveniences。为此使用适当的资源处理类。例如,std::vector是您应该用来管理动态分配的数组的。


要回到手头的问题,首先需要知道delete [] _perm[i]的作用:它为该数组中的每个Chromosome对象调用析构函数,然后释放内存。现在你在循环中执行此操作,这意味着它将调用 所有 Chromosome析构函数并执行f解除分配。正如在对您的问题的评论中已经提到的那样,非常可能Chromosome 析构函数是真正的罪魁祸首 。试着调查一下。


但是,您可以更改内存处理以提高分配和释放的速度。 As Nawaz has shown,您可以分配 一大块内存 并使用它。我使用std::vector作为缓冲区:

void f(std::size_t row, std::size_t col)
{
  int sizeMemory = sizeof(Chromosome) * row * col;
  std::vector<unsigned char> buffer(sizeMemory); //allocation of memory at once!

  vector<Chromosome*> chromosomes(row);

  // use algorithm as shown by Nawaz
  std::size_t j = 0 ;
  for(std::size_t i = 0 ; i < row ; i++ )
  {
      //...
  }

  make_baby(chromosomes); //use chromosomes

  in_place_destruct(chromosomes.begin(), chromosomes.end());

  // automatic freeing of memory holding pointers in chromosomes
  // automatic freeing of buffer memory
}

template< typename InpIt >
void in_place_destruct(InpIt begin, InpIt end)
{
  typedef std::iterator_traits<InpIt>::value_type value_type; // to call dtor
  while(begin != end)
    (begin++)->~value_type(); // call dtor
}

但是,尽管通过std::vector 处理所有内存,但这仍然不是完全异常安全的 ,因为它需要调用Chromosome析构函数明确。 (如果make_baby()抛出异常,函数f()将提前中止。虽然向量的析构函数将删除其内容,但只有一个包含指针,另一个将其内容视为原始内存。警卫正在监视在原始记忆中创建的实际对象。)


我能看到的最佳解决方案是使用包含在 二维访问的类中的 一维数组 > 到该数组中的元素。 (内存毕竟是一维,在当前的硬件上,所以系统已经这样做了。)以下是草图:

class chromosome_matrix {
public:
  chromosome_matrix(std::size_t row, std::size_t col)
   : row_(row), col_(col), data_(row*col)
  {
    // data_ contains row*col constructed Chromosome objects
  }

  // note needed, compiler generated dtor will do the right thing
  //~chromosome_matrix()

   // these rely on pointer arithmetic to access a column
        Chromosome* operator[](std::size_t row)       {return &data_[row*col_];}
  const Chromosome* operator[](std::size_t row) const {return &data_[row*col_];}

private:
  std::size_t row_;
  std::size_t col_;
  std::vector<chromosomes> data_
};

void f(std::size_t row, std::size_t col)
{
  chromosome_matrix cm(row, col);

  Chromosome* column = ch[0];          // get a whole column
  Chromosome& chromosome1 = column[0]; // get one object

  Chromosome& chromosome2 = cm[1][2];  // access object directly

  // make baby
}

答案 2 :(得分:1)

我建议你使用贴新品。分配和释放可以在每个语句中完成!

int sizeMemory = sizeof(Chromosome) * row * col;
char* buffer = new char[sizeMemory]; //allocation of memory at once!

vector<Chromosome*> chromosomes;
chromosomes.reserve(row);
int j = 0 ;
for(int i = 0 ; i < row ; i++ )
{
    //only construction of object. No allocation!
    Chromosome *pChromosome = new (&buffer[j]) Chromosome[col]; 
    chromosomes.push_back(pChromosome);
    j = j+ sizeof(Chromosome) * col;
}

for(int i = 0 ; i < row ; i++ )
{
      for(int j = 0 ; j < col ; j++ )
      {
         //only destruction of object. No deallocation!
         chromosomes[i][j].~Chromosome();
      }
}
delete [] buffer; //actual deallocation of memory at once!

答案 3 :(得分:0)

std :: vector可以提供帮助。

特殊内存分配器。