Hei社区,
我有一个关于删除指针的小问题。
我正在使用Dimension 1024x1024的指针指针矩阵。由于我是动态创建的,因此我在程序结束时删除了为它们分配的空间。但是在通常的循环中执行此操作会花费相当多的时间 - 我使用处理器的时钟速率测量了大约2秒。当程序运行仅15秒时,2秒是巨大的 - 加上:使用这些分配的指针的函数被调用超过一次......。
以下是测量的时间关键代码,包括测量:
time=clock();
for(i=0;i<xSize;i++){ //xSize is dynamic, but 1024 for the measurement
delete [] inDaten[i];
delete [] inDaten2[i];
delete [] copy[i];
}
delete inDaten; delete inDaten2; delete copy;
time=clock()-time;
time/=CLOCKS_PER_SEC;
删除指针总是这么久吗?或者我只是以错误的方式做事?
我希望有人可以帮助我解决这个问题。由于我正在优化一个非常复杂的程序以便更快地运行,因此我无法使用这些2秒的代码。与所有其他部分相比,它的速度太慢了。但我仍然需要能够动态地实现这个代码。 SmartPointers可能会有所帮助,但如果我理解正确,他们也需要时间来删除自己 - 只是在不同的时间......
感谢您的回答!
Baradrist
编辑:我刚刚发现,测量这些删除计算的速度非常慢,因为我没有在发布模式下编译它。由于调试器发挥作用,我测量了这些(最终不真实的)数字让我头疼。最终程序自动优化,以便几乎不再有任何时间参与删除。无论如何:感谢所有有用的答案!他们给了我很多额外的知识和事情要考虑!!!!
答案 0 :(得分:3)
delete[]
也会为数组的每个元素调用析构函数,这会增加时间,除非析构函数很简单。
除此之外 - 是的,动态内存分配相对昂贵。如果你不能容忍它 - 尝试分配更小的更大的块或者在时间关键的东西中没有动态分配。
智能指针无济于事 - 它们将在内部进行相同的释放。它们不是为了加速,而是为了设计方便。
答案 1 :(得分:2)
这是一个有趣的主题“Memory Allocation/Deallocation Bottleneck?”
分配和解除分配需要很长时间,因此是您拥有的最常见的高成本操作之一。这是因为堆管理必须处理一堆事情。通常在调试模式下还会对内存块进行更多检查。如果您在发布配置中有相同的时间,我会感到惊讶,通常在至少2之间有一个因素。使用私有堆,您可以大大增加事情。如果您始终分配相同大小的对象,则内存池可能是最佳选择。
答案 2 :(得分:1)
如果在程序结束时删除它们并且无法运行多个析构函数,只需省略删除 - 操作系统将释放内存。否则,尝试使用单个间接,即没有指向指针的数组。除了减少删除时间,这也将改善参考的位置。
答案 3 :(得分:1)
看起来问题出在数据结构中。为什么需要这么多动态分配?可以采取哪些措施来减少分配数量?
如果释放指针需要2秒钟,那么分配它们的时间可能至少相同。
只需提前退出程序即可避免释放它们。 C ++不保证当前分配的内存会发生什么,但是你的操作系统可能会这样做,所以在实用术语中,它可能是一个简单的方法来减少执行时间2秒。
但是仍然留下了&gt;分配时间为2秒。
我认为,最好的办法是尝试更好地构建数据。您能告诉我们目前矩阵的结构吗?
答案 4 :(得分:1)
不应该是:
delete [] inDaten; delete [] inDaten2; delete [] copy;
因为使用它们显然是数组。 (至少他们看起来也是如此,你没有提供足够的背景)。
答案 5 :(得分:1)
你没有说数组中的对象有多大,但是如果它们足够大,那么部分内存可能被换出并需要重新交换(或者可能只是重新映射回进程)空间),这导致你看到的时间。
答案 6 :(得分:0)
尝试创建自己的内存分配方法,以便减少销毁时间。
例如,从Os请求一块内存并将数组分配给它,以便您可以在一个操作中释放整个块。
答案 7 :(得分:0)
非常感谢所有快速答案!很高兴看到有人帮助=)。仍然为我的问题似乎我必须处理这种时间损失,因为我需要动态数组作为较小的子程序中的临时矩阵,而不是在最后执行。
无论如何:再次感谢!!祝你有愉快的一天!
Baradrist
答案 8 :(得分:0)
如果数组中指向的对象具有非平凡的析构函数,那么在没有首先解决的情况下,您可以做很多事情来显着改善运行时。否则:
为什么不将大小为inDaten, inDaten2 and copy
的数组指向大小为isize
的数组的isize
数组,而不是使用以下内容来处理单个项目: isize*isize
使用array[i][j]
解决这些问题。
这样您就可以通过拨打array[i*isize+j]
来清理。
答案 9 :(得分:0)
对此的优化是以块的形式分配内存,使用placement new分配单个指针,删除后只删除整个块。
你必须要小心,因为这个选项隐含地不会为使用placement new分配的每个对象调用析构函数。
答案 10 :(得分:0)
如果您已确定内存分配/解除分配是瓶颈并希望更快,那么第一个明显的解决方案是为阵列使用连续缓冲区。您仍然可以提供一个矩阵接口,可以像二维数组一样访问它们。
// Rudimentary Implementation
template <class T>
class SquareMatrix
{
public:
explicit SquareMatrix(int i_size):
size(i_size), mat(new T[i_size * i_size]) {}
~SquareMatrix()
{
delete[] mat;
}
// could also be column depending on row-major/col-major
T* operator[](unsigned int row)
{
return mat + row * size;
}
// could also be column depending on row-major/col-major
const T* operator[](unsigned int row) const
{
return mat + row * size;
}
private:
unsigned int size;
T* mat;
};
第二个显而易见的事情是,有一个矩阵由一个包含你需要的所有数据的结构组成,而不是三个矩阵。这假设一个元组矩阵就足够了,这就像你发布的代码一样。
如果你真的想要硬核并需要多个矩阵,那么为此编写自己的内存分配器。您可以一次为多个矩阵分配内存,只需使用placement new构建它们。如果你想这样做需要进一步阅读和学习,因为编写内存分配器并不是一项简单的任务:你需要考虑对齐等问题,但这是最快的方法。
我建议您仍然使用分析器,而不是依赖于时序测试,并对代码进行正确的调用图分析。这将告诉你究竟花了多少时间在哪里。例如,可能是矩阵中物体的构造/破坏并不像它那样便宜。
缺乏明显的算法效率低下,即使是知识渊博的程序员也常常对其代码中的瓶颈不正确。如果效率是一个主要问题,那么探查器是你最好的朋友。
答案 11 :(得分:0)
如果矩阵中指针引用的所有对象都是相同的类型(或者至少是相同的大小),则可以分配一大块内存来保存它们并就地初始化它们。