2011-03-08 32 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中明确指定自定义分配器。结果应该非常实用和易于使用 - 像对象池一样的基于价值的自定义内存分配器(据我所知)非常容易插入。