我写了一个程序,它计算流水车间调度问题。
我需要帮助优化程序中最慢的部分:
首先是数组2D数组分配:
this->_perm = new Chromosome*[f];
//... for (...)
this->_perm[i] = new Chromosome[fM1];
它工作得很好,但是当我尝试删除数组时会出现问题:
delete [] _perm[i];
执行上面的行需要很长时间。 Chromosome
是大约300k元素的数组 - 分配它只需不到一秒钟,但删除时间远远超过一分钟。
我很感激任何改进删除部分的建议。
答案 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可以提供帮助。
特殊内存分配器。