2011-03-08 56 views
1

我寫基於事件的模擬器,其中,每個事件調用的處理功能(節點),其可以產生新的事件,等等。 時間戳被關聯到每個事件,並需要在增加的時間(但事件不一定按該順序創建的)的順序進行處理。爲此,我使用一個簡單的priority_queue<Event*>,其中Event是一個包含指向必須調用的處理節點的指針和時間戳的類。池內存分配在一個優先級隊列

所以,一切正常,但我得到了數百萬事件分配和每秒釋放,這顯然是什麼限制了我的模擬器的速度(大約30%的執行時間是由內存分配和釋放事件對象)。

我發現這個問題: Object pool vs. dynamic allocation,它似乎我可以非常受益於對象池。雖然我看到Boost提供了一些方法來實現這一點,但我不確定要明白這是否適用於在priority_queue中實現池。當涉及到自定義內存分配時,我真的迷失了方向。

所以我的問題是:會是實用的/有益的使用對象池我priority_queue,如果是,有一個簡單的方法來做到這一點,有可能一些代碼示例(或至少是一個開始點),最好不要立即依靠Boost第一次?

竟有些裁判明白池分配的工作方式也將受到歡迎!

謝謝。

+0

只需確保爲您的應用程序預分配一個大塊在初始化池中,您需要做一些測量,以瞭解在任何時候需要的最高數量的項目,以完全避免動態分配 – lurscher 2011-03-11 17:58:14

回答

0

對象池的快速和骯髒的例子

EventPool.h

#include <stack> 
class Event; 

class EventPool 
{ 
public: 
    explicit EventPool(const unsigned int initSize = 0); 
    ~EventPool(); 
    Event* getEvent(); 
    void returnEvent(Event* e); 
private: 
    std::stack<Event*> pool_; 
}; 

EventPool.cxx

#include <Event.h> 
#include <EventPool.h> 

EventPool::EventPool(const unsigned int initSize) 
{ 
    for(unsigned int i = 0; i < initSize; ++i) 
    { 
     pool_.push(new Event()); 
    } 
} 

EventPool::~EventPool() 
{ 
    while(!pool_.empty()) 
    { 
     delete pool_.top(); 
     pool_.pop(); 
    } 
} 

Event* EventPool::getEvent() 
{ 
    if(pool_.empty()) 
    { 
     return new Event(); 
    } 
    Event* returnValue = pool_.top(); 
    pool_.pop(); 
    return returnValue; 
} 

void EventPool::returnEventToPool(Event* e) 
{ 
    pool_.push(e); 
} 

這樣做這個,你可以讓池控制自己的大小。當另一個對象抓取一個事件時,抓取器要麼將事件返回,要麼將其刪除。

+0

我喜歡這個例子,它非常簡單,適應我正在做的事情,它給了我性能提升5至10%。現在,我想知道是否還可以通過直接向我的priority_queue的容器提供自定義分配器來獲得更多改進,正如其他答案所建議的那樣?在__adjust_heap和__push_heap中仍有大約25%的執行時間,但我想這可能是不可避免的!如果我有一段時間,我可能會嘗試提高... – OlivierB 2011-03-11 12:04:37

+0

很高興幫助!我添加了一個編輯來顯示將堆棧初始化爲給定大小,包括初始化第一組對象。這使得你的游泳池有點沉重(前期成本),但希望避免額外的施工。您需要爲'initSize'選擇一個最佳值,因爲更大的啓動池大小意味着更大的內存佔用量。 – spbots 2011-03-11 17:35:27

0

我猜你談論std::priority_queue。是的,可以提供您自己的分配方案。

STL優先級隊列是以另一個容器(默認情況下,我認爲是std::vector)實現的,它可以被指定爲模板參數。然後你可以用你的分配器參數化這個其他容器(按照通常的STL方式)。

它然後保持分配器的實現。如果你不想自己做,我很確定你可以在那裏找到很多(例如你提到Boost)。我曾經使用a segregated pool implementation from here進行了一些小修改。它做的相當不錯...

1

是的,這是很實際的這樣做。請記住,內置的動態分配器對於每個用途都儘可能快 - 也就是說,它必須分配和取消分配任何大小,任何類型和任何順序。如果您事先知道這不是必要的,那麼可以大大降低分配和取消分配的複雜性。

在這種情況下,您事先知道您總是分配一個事件。這使得對象池成爲您的目的的優秀分配器。將用於STL對象的自定義分配器添加到std::priority_queue是非常實用的 - 隊列模板化在內部容器上,默認爲std::vector,您可以在std::vector中明確指定自定義分配器。結果應該非常實用和易於使用 - 像對象池一樣的基於價值的自定義內存分配器(據我所知)非常容易插入。