我当前的项目实现了一个对象池,以避免为了速度目的而进行常量内存分配和解除分配,对象池是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());
答案 0 :(得分:1)
通常,对象池使用 aging 来确定何时驱逐单个池对象。
这样做的一种方法是在更新循环中保留迭代计数器。每个循环都会递增此计数器。每个对象可以保持“最后一个活动”时间(循环计数是对象活动的最后一次)。非活动对象将被移动到数组的末尾,并且当足够大时将被驱逐(销毁)。将保留最后一个活动对象的单独索引,因此在遇到此更新时可能会停止更新循环。
如果无法在对象中存储活动时间,您仍然可以将非活动对象移动到活动列表的末尾,如果有太多非活动对象,则将列表缩小一些。
答案 1 :(得分:1)
您应该指定清理的成本,以及池的大小,它们会影响应该如何实施清理。
为了清楚起见,池实际上是一种对象的分配器,性能增益完全独立于清理单个对象的方式。
我不能每帧清理矢量,因为这会破坏性能。
如果非活动对象的清理性能占主导地位,那么在池算法中无法做任何事情。
因此我假设这是由$ sed --version | head -1
sed (GNU sed) 4.4
语义引起的,其中删除非活动对象涉及重定位其他对象。那么问你真的需要std::vector
的属性是合乎逻辑的吗?
std::vector
就可以了。如果答案是否定的,那么只需使用std::vector
和std::deque
等内容,其中删除为O(1),您可以在每个帧上进行清理。
否则您的池的垃圾收集可以作为
完成