2011-03-07 81 views
3

通過預先分配堆內存並遞增填充,性能有很大提高嗎?優化:在多個對象使用之前預先分配一堆堆內存 - GAINS?

考慮以下這個非常簡單的例子:

byte * heapSpace = malloc (1 000 000); 
int currentWriteSpot = 0; 

struct A { 
    int x; 
    byte * extraSpace; 
    int extraSpaceLength; 
}; 

//a1 needs 10 bytes of extra storage space: 
A a1; 
a1.x = 2; 
a1.extraSpace = heapSpace + currentWriteSpot; 
a1.extraSpaceLength = 10; 

currentWriteSpot += 10; 

//a2 needs 120 bytes of extra storage space: 
A a2; 
a2.x = 24; 
a2.extraSpace = heapSpace + currentWriteSpot; 
a2.extraSpaceLength = 120; 

currentWriteSpot += 120; 

// ... many more elements added 

for (...) { 
    //loop contiguously over the allocated elements, manipulating contents stored at "extraSpace" 
} 

free (heapSpace); 

VS:

... 
a1.extraSpace = malloc (10); 
a2.extraSpace = malloc (120); 
a3... 
a4... 
... 

//do stuff 

free (a1.extraSpace); 
free (a2.extraSpace); 
free ... 
free ... 
free ... 

或者這可能只是在性能上沒有顯著的收益增加了複雜性?

謝謝大家!

+0

肯定是內存管理器會爲你做到這一點? – 2011-03-07 22:15:40

+0

你在C或C++嗎? – Puppy 2011-03-07 22:53:43

+0

代碼示例本來是模糊的,但我會實際上是在C++中,Windows XP,Win7的合作,並建立Linux的變種 – 2011-03-07 22:59:31

回答

4

首先,這樣做不會增加複雜性;它會降低它。由於您在操作開始時已經確定malloc已成功,因此您不需要對失敗進行任何進一步檢查,這至少需要已分配的free,並且可能會顛倒各種對象狀態的其他更改。

正如您所指出的,其他好處之一是性能。在多線程程序中,這將是一個更大的問題,其中調用malloc可能會導致鎖爭用。

也許一個更重要的好處是避免碎片。如果整個數據對象被分配在一起而不是分成小塊,釋放它肯定會將整個大小的可用連續空間返回到空閒內存池,供以後的分配使用。另一方面,如果分別分配每個小塊,則很可能它們不會連續。

除了減少碎片,所有的數據作爲單個連續塊分配也避免了每次分配開銷(每個分配至少8-16個字節被浪費),並改善數據局部性緩存的目的。

順便說一句,如果你發現這種分配策略過於複雜,你可以嘗試做了一些功能來爲您處理,或使用像GNU obstack現有的庫。

1

通常最好讓內存管理器做這種事情,但是在一些極端的情況下(比如小的分配和解除分配)可以使用自己的實現來更好地處理。 IE瀏覽器。你抓住一大塊內存並根據需要分配/釋放。通常情況下,這種情況將會非常簡化(例如,您擁有稀疏矩陣實現),您可以在其中應用標準內存管理器無法執行的特定於域的優化。例如。在稀疏矩陣的例子中,每塊內存將會是相同的大小。這使得垃圾收集相對簡單 - 大塊的解除分配內存不需要加入 - 只需要一個簡單的「使用中」標誌等等。

+1

我剛剛更新的問題,確實內存管理器(是操作系統的一部分? )智能地管理資源,這樣我就可以編寫我的代碼作爲示例的第二部分演示,而不會遭受性能命中? (在大多數情況下,如你所建議的) – 2011-03-07 22:28:11

4

您希望這樣做的原因是,如果您需要保證一致的分配時間(其中'一致'!='最快')。最大的例子是遊戲或其他繪畫操作的繪製循環 - 對於它來說,不是爲了「打嗝」而是以犧牲一致性爲代價獲得額外的2 FPS更重要。如果你只想儘可能快地完成一項操作,那麼Win7 LFH是相當快的,並且已經爲你做了這個優化(這個技巧是從堆管理器通常被吸引的時候開始的,而且是真的慢)。話雖如此,我可能是完全錯誤的 - 總是分析你的工作量,看看哪些是有效的,哪些沒有。

+0

任何想法Windows XP如何處理堆碎片? – 2011-03-07 22:47:09

+0

沃瑟:)如果通過實驗你發現堆是相當分散和malloc()函數越來越隨着時間的推移慢,你可以使用類似Mozilla的jemalloc,但除非你的網頁瀏覽器分配儘可能多的對象,我不認爲你不必擔心。 – 2011-03-07 22:50:07

0

你應該只向內存管理器請求儘可能多的內存塊,因爲你需要單獨控制 - 當然,在理想的世界裏我們有無限的優化時間。如果有幾個A對象不需要單獨生活,那麼不要單獨分配它們。

當然,這是否真的值得更強化的優化時間,是另一個問題。

+0

的確,複雜性會出現,但是,因爲(如我所指出的)每個對象的分配大小都是可變的。我希望能夠提前知道要拋開多少內存......但我不這樣做。因此,儘管所有對象都會共享相同的生命週期,但很難利用這一優勢。 – 2011-03-07 22:57:22

+0

@J T:如果你知道在分配時,這就是你需要 - 你不能在不知道多少反正分配,所以當你分配他們必須知道分配對象。 – Puppy 2011-03-08 11:48:03