1

我正在编写一个基于事件的模拟器,其中每个事件都调用一个可以生成新事件的处理函数(节点),依此类推。时间戳与每个事件相关联,它们需要按时间增加的顺序进行处理(但事件不一定按该顺序创建)。为此,我使用了一个简单的priority_queue<Event*>,其中 Event 是一个类,其中包含指向必须调用的处理节点的指针和时间戳。

所以,一切正常,但我每秒分配和释放数百万个事件,这显然是限制我的模拟器速度的原因(大约 30% 的执行时间由 Event 对象的内存分配和释放占用)。

我发现了这个问题: 对象池与动态分配,似乎我可以从对象池中受益匪浅。虽然我已经看到 Boost 提供了一些方法来做到这一点,但我不确定这对于在priority_queue. 当谈到自定义内存分配时,我真的很迷茫。

所以我的问题是:为 my 使用对象池是否实用/有益priority_queue,如果是,是否有一种简单的方法可以做到这一点,可能有一些代码示例(或至少一个起点),最好不要立即依赖第一次使用Boost?

实际上,也欢迎一些参考来了解池分配的工作原理!

谢谢。

4

3 回答 3

1

是的,这样做非常实用。请记住,内置动态分配器被构建为尽可能快地用于各种目的——也就是说,它必须以任何大小、任何类型和任何顺序分配和取消分配。如果你事先知道这没有必要,你可以大大降低分配和解除分配的复杂性。

在这种情况下,您提前知道您总是在分配一个事件。这使对象池成为您的目的的优秀分配器。将设计用于与 STL 对象一起使用的自定义分配器添加到 a 是非常实用的std::priority_queue- 队列在内部容器上模板化,std::vector默认情况下,您可以在 a 中显式指定自定义分配器std::vector。结果应该是非常实用且易于使用的——基于值的自定义内存分配器,如对象池(据我所知)相当容易插入。

于 2011-03-08T22:57:04.450 回答
0

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

STL 优先级队列是根据另一个容器(std::vector我认为默认情况下)实现的,可以将其指定为模板参数。然后你可以用你的分配器参数化这个另一个容器(以通常的 STL 方式)。

它仍然是分配器的实现。如果您不想自己做,我很确定您可以在那里找到很多(例如,您提到了 Boost)。我曾经从这里使用过隔离池实现,并进行了一些小的修改。它做得相当好...

于 2011-03-08T22:40:41.900 回答
0

一个快速而肮脏的对象池示例

事件池.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_;
};

事件池.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);
}

通过这样做,您可以允许池控制自身的大小。当另一个对象抓取一个事件时,由抓取器决定是否返回该事件或将其删除。

于 2011-03-08T22:51:36.710 回答