在循环内部分配内存vs外部循环

问题描述:

在循环的每次迭代中分配堆内存的大块是否会有明显的性能损失?当然,我在每次迭代结束时都会释放它。在循环内部分配内存vs外部循环

另一种方法是在进入循环之前分配一次,在所有迭代中重复使用它,并最终在退出循环后释放它。请参阅下面的代码。

// allocation inside loop 
for(int i = 0; i < iter_count; i++) { 
    float *array = new float[size](); 
    do_something(array); 
    delete []array; 
} 

// allocation outside loop 
float *array = new float[size](); 
for(int i = 0; i < iter_count; i++) { 
    do_something(array); 
} 
delete []array; 

  • 即使分配是固定的时间,你也有TxN而不是T.另外,如果你有任何内存块初始化(即使它只是设置为零),你反复地重复你的缓存。
  • 堆分配的主要性能影响是碎片化,而不是分配时间,这是一个累积性问题。收集更少。

  • 有一些病理性病例。如果有大量的短期分配活动“跨越”大块的释放和分配(例如,在另一个线程中运行相同的例程),那么您可能经常推动堆管理器为大块需要新内存(因为它现在是占据)。这将真正分解您的缓存并增加您的工作集。

所以这是直接命中,可直接测量:多少钱new/delete成本相比do_something()?如果do_something价格昂贵,则可能衡量不多。

在大型应用程序中积累了“堆压力”。对此的贡献很难衡量,你可能会遇到由十几个独立贡献者构建的性能砖墙,事后很难识别。

除非你测试它有多大,否则实际上不知道,但如果没有理由在循环内部分配它,则不需要。分配大量内存可能会很慢,如果你做得够多,它会减慢你的代码。
同样的事情可以说是循环内的任何东西。如果它不需要在那里,它会运行得更快,如果它被取出(快多快完全取决于它是什么,分配内存比其他东西更苛刻),但如果它使代码更好/更容易,它可以值得让它留在循环中。

+1

是的,Aamir应该只是进行测试。他已经写了上面的测试代码。无需推测 - 只需尝试一下。科学! – 2010-08-05 05:53:18

开销取决于do_something()的“权重”。当它作用于一个数组时,我认为这比一些标量操作要多一点。所以在这种情况下,您不会通过在循环外部移动分配/删除来注意到任何加速。但是,在上面所示的情况下,没有理由不这样做。

我永远不会在循环中做它。分配内存不是免费事件,并且一次执行一次是肯定是一遍又一遍地重复执行。 您也可以只分配阵列没有括号,你应该罚款:

float *array = new float[size]; 

移动操作移出循环可以提高性能。如果iter_count较大,则外部分配将更快。

new()运算符潜在地(但并非总是)会导致操作系统调用获取更多内存,这相对昂贵(相对而言)。同样,delete()调用也可能会释放内存(但并非总是如此!),从而也会导致操作系统调用。

在所有情况下,确保do_something()不会对其未初始化的内存内容做任何假设,并且可能包含随机数据。