根据执行时间清理对象池

时间:2017-05-10 00:45:39

标签: c++ performance vector timer object-pooling

问题

我当前的项目实现了一个对象池,以避免为了速度目的而进行常量内存分配和解除分配,对象池是std::vector<object>,我想实现一种垃圾收集形式,以减少内存使用和提高性能。程序遍历整个向量的每个循环,如果对象处于活动状态,则执行更新函数,这意味着如果我的向量中充满了非活动对象,我将浪费大量时间迭代它们以及存储它们的内存。我不能每帧清理矢量,因为这会破坏性能。

当前尝试

我目前尝试实现这一目标的方法是测量更新时间,并使用预定义的函数来确定我们是否在更新上花费了太多时间,因为我们是当前活动的对象数量,我清理矢量一次,让速度恢复正常。

#include <chrono>

void updateObjects()
{
  auto begin = std::chrono::high_resolution_clock::now();
  //update all objects
  for(auto o : objectVec)
  {
    //only update active objects
    if(o.m_alive)
    {
      o.update();
    }
  }
  //end time of update
  auto end = std::chrono::high_resolution_clock::now();
  //calculate time taken vs estimated time
  auto elapsed = (end-begin).count();
  //Estimate is based on performance testing
  long estimate = 25*m_particleCount+650000;

  //If we have no active objects, 
  //but are wasting memory on storing them, we clean up
  //If the update takes longer than it should, we clean up
  if(((objectCount <= 0) && (objectVec.size() > 0)) || (elapsed > estimate))
  {
    cleanVec(); //remove inactive objects
  }
}

此解决方案在我的电脑上运行良好,但我在其他计算机上遇到问题,因为更新完成所需的时间因CPU速度不同而有所不同,因此我的预定义功能不起作用是基于不正确的数据。我想知道是否还有其他测量可用于此计算?有没有办法可以衡量执行的纯指令数量,因为这在计算机上是相同的,有些人会更快地执行它们吗?欢迎任何其他建议,谢谢!

修改

对象池可以大到100,000个对象,典型使用范围从3000到最大。 我的清洁功能是:

objectVec.erase(std::remove_if(objectVec.begin(),
                               objectVec.end(),
                               [](const object& o) {return !(o->m_alive);}),
                               objectVec.end());

2 个答案:

答案 0 :(得分:1)

通常,对象池使用 aging 来确定何时驱逐单个池对象。

这样做的一种方法是在更新循环中保留迭代计数器。每个循环都会递增此计数器。每个对象可以保持“最后一个活动”时间(循环计数是对象活动的最后一次)。非活动对象将被移动到数组的末尾,并且当足够大时将被驱逐(销毁)。将保留最后一个活动对象的单独索引,因此在遇到此更新时可能会停止更新循环。

如果无法在对象中存储活动时间,您仍然可以将非活动对象移动到活动列表的末尾,如果有太多非活动对象,则将列表缩小一些。

答案 1 :(得分:1)

您应该指定清理的成本,以及池的大小,它们会影响应该如何实施清理。

为了清楚起见,池实际上是一种对象的分配器,性能增益完全独立于清理单个对象的方式。

  

我不能每帧清理矢量,因为这会破坏性能。

如果非活动对象的清理性能占主导地位,那么在池算法中无法做任何事情。

因此我假设这是由$ sed --version | head -1 sed (GNU sed) 4.4 语义引起的,其中删除非活动对象涉及重定位其他对象。那么问你真的需要std::vector的属性是合乎逻辑的吗?

  • 你是否需要你的物品在记忆中连续?
  • 您是否需要O(1)随机访问?
  • 你经常在游泳池上游吗?
  • 否则,游泳池小吗?只要它很小std::vector就可以了。

如果答案是否定的,那么只需使用std::vectorstd::deque等内容,其中删除为O(1),您可以在每个帧上进行清理。

否则您的池的垃圾收集可以作为

完成
  • 保留自上次为每个对象更新后的帧计数器,如果计数器超过阈值则删除
  • 保留非活动对象总数的计数器,如果活动对象的百分比超过阈值,则清理池