我正在编写一个基于事件的模拟器,其中每个事件都调用一个可以生成新事件的处理函数(节点),依此类推。
时间戳与每个事件相关联,并且它们需要按照增加的时间顺序进行处理(但事件不一定按该顺序创建)。为此,我使用了一个简单的priority_queue<Event*>
,其中Event是一个包含指向必须调用的处理节点的指针和时间戳的类。
所以,一切正常,但我每秒分配和释放数百万个事件,这显然限制了我的模拟器的速度(大约30%的执行时间是由内存分配和事件对象的释放占用的)。
我发现了这个问题:
Object pool vs. dynamic allocation似乎我可以从对象池中受益匪浅。虽然我已经看到Boost提供了一些方法来做到这一点,但我不确定这是否适用于在priority_queue
中实现池。在定制内存分配方面,我真的很失落。
所以我的问题是:为我的priority_queue
使用对象池是否实用/有益,如果是,有一种简单的方法可以做到这一点,也许有些代码示例(或至少是一个起点),最好不要在第一时间立即依赖Boost?
实际上有些人会理解游泳池分配如何运作也是受欢迎的!
感谢。
答案 0 :(得分:1)
是的,这样做非常实用。请记住,内置的动态分配器可以为每个目的尽可能快地构建 - 也就是说,它必须分配和取消分配任何大小,任何类型和任何顺序。如果您事先知道这不是必要的,那么您可以大大降低分配和解除分配的复杂性。
在这种情况下,您事先知道您总是分配一个事件。这使得对象池成为您的目的的优秀分配器。添加一个自定义分配器是非常实用的,该分配器设计用于与std::priority_queue
的STL对象 - 该队列在内部容器上进行模板化,默认为std::vector
,您可以明确指定std::vector
中的自定义分配器。结果应该非常实用且易于使用 - 像对象池一样基于值的自定义内存分配器(据我所知)相当容易插入。
答案 1 :(得分:0)
我想你在谈论std::priority_queue
。是的,可以提供自己的分配方案。
STL优先级队列是根据另一个容器(我认为是std::vector
)实现的,可以指定为模板参数。然后,您可以使用分配器(以通常的STL方式)参数化其他容器。
它仍然是分配器的实现。如果您不想自己动手,我很确定您可以找到很多(例如,您提到过Boost)。我曾经使用a segregated pool implementation from here进行了一些小修改。它做得很好......
答案 2 :(得分: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);
}
通过执行此操作,您可以允许池控制自身的大小。当另一个对象抓取一个事件时,由抓取器决定是给予事件还是删除它。