2010-08-05 459 views
2

在循環的每次迭代中分配堆內存的大塊是否會有明顯的性能損失?當然,我在每次迭代結束時都會釋放它。在循環內部分配內存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; 

回答

2
  • 即使分配是固定的時間,你也有TxN而不是T.另外,如果你有任何內存塊初始化(即使它只是設置爲零),你反覆地重複你的緩存。
  • 堆分配的主要性能影響是碎片化,而不是分配時間,這是一個累積性問題。收集更少。

  • 有一些病理性病例。如果有大量的短期分配活動「跨越」大塊的釋放和分配(例如,在另一個線程中運行相同的例程),那麼您可能經常推動堆管理器爲大塊需要新內存(因爲它現在是佔據)。這將真正分解您的緩存並增加您的工作集。

所以這是直接命中,可直接測量:多少錢new/delete成本相比do_something()?如果do_something價格昂貴,則可能衡量不多。

在大型應用程序中積累了「堆壓力」。對此的貢獻很難衡量,你可能會遇到由十幾個獨立貢獻者構建的性能磚牆,事後很難識別。

2

除非你測試它有多大,否則實際上不知道,但如果沒有理由在循環內部分配它,則不需要。分配大量內存可能會很慢,如果你做得夠多,它會減慢你的代碼。
同樣的事情可以說是循環內的任何東西。如果它不需要在那裏,它會運行得更快,如果它被取出(快多快完全取決於它是什麼,分配內存比其他東西更苛刻),但如果它使代碼更好/更容易,它可以值得讓它留在循環中。

+1

是的,Aamir應該只是進行測試。他已經寫了上面的測試代碼。無需推測 - 只需嘗試一下。科學! – 2010-08-05 05:53:18

0

開銷取決於do_something()的「權重」。當它作用於一個數組時,我認爲這比一些標量操作要多一點。所以在這種情況下,您不會通過在循環外部移動分配/刪除來注意到任何加速。但是,在上面所示的情況下,沒有理由不這樣做。

3

我永遠不會在循環中做它。分配內存不是免費事件,並且一次執行一次是肯定是一遍又一遍地重複執行。 您也可以只分配陣列沒有括號,你應該罰款:

float *array = new float[size]; 
0

移動操作移出循環可以提高性能。如果iter_count較大,則外部分配將更快。

new()運算符潛在地(但並非總是)會導致操作系統調用獲取更多內存,這相對昂貴(相對而言)。同樣,delete()調用也可能會釋放內存(但並非總是如此!),從而也會導致操作系統調用。

在所有情況下,確保do_something()不會對其未初始化的內存內容做任何假設,並且可能包含隨機數據。