我正在制作一款需要高性能的视频游戏,所以我正试图设置一个好的记忆策略或游戏的特定部分,即游戏“模型”,即游戏表现。我有一个包含整个游戏表示的对象,里面有不同的管理器,以保持表示符合游戏规则。每个游戏实体当前都是由特定类型的工厂生成的,所以我有几个工厂允许我按照自己的意愿隔离和更改这些实体的内存管理。
现在,我正在选择这两种选择之间:
现在,我对A有了一些真实的经验,所以我对B没有经验,并希望对这些解决方案提出一些建议。 对于长寿命项目来说哪个解决方案似乎更好?为什么?(注意:在这种情况下,游泳池是非常必要的,因为游戏模型也用于游戏编辑,所以会有很多分配/解除分配小物件)。
编辑澄清:如果(目前尚不清楚)我正在使用C ++
答案 0 :(得分:8)
正确答案特定于您的问题域。但在我工作的问题域中,第一个通常是我们选择的域。
我做实时或接近实时的代码。主要是音频编辑和播放。在该代码中,我们通常不能在回放引擎中从堆中分配内存。大多数情况下malloc返回的速度足够快,但有时却没有。这有时很重要。
因此,我们的解决方案是为特定对象设置特定池,并将通用池用于其他所有对象。特定池具有预先分配的一定数量的元素,并且实现为链接列表(实际上是队列),因此分配和释放永远不会超过几个指针更新以及进入和离开关键部分的成本。
作为不寻常案件的后备;当有人需要从特殊池分配并且它是空的时 - 我们将分配一大块通用内存(几个对象)并将其添加到特殊池中。一旦分配成为特殊池的一部分,它将永远不会返回到通用池,直到应用程序退出或启动新项目。
对特殊池的初始大小和最大大小做出正确选择是调整应用程序的重要部分。
答案 1 :(得分:4)
您将遇到的一个问题是允许STL实现假设两个相同类型的分配器是等效的。这就是Boost.Pool只使用一个池的原因(从技术上讲,它为每种类型使用不同的池)。 I.E.,在一般情况下,您的分配器不允许有任何非静态成员。如果您正在制作视频游戏而且您知道您的STL实施没有此问题,那么请不要担心这一点 - 但list::splice
和std::swap
上可能仍存在一些问题容器
答案 2 :(得分:4)
对于初学者来说,对任何类型的视频游戏使用stl或boost都是不切实际的。你可以绝对肯定第二个你使用一个stl容器,你的内存是碎片化的,你的性能在厕所中是绝对的,至少与理想相比(因为大多数人的代码都在这个类别中,大多数人从来没有注意到,也无法真正比较还要别的吗)。我并不总是如此强烈地思考,但随着时间的推移,我甚至看到几行代码就像一个小小的gremlin,最终有一天会给你带来巨大的痛苦。
第一种方法是最常见的,如果你不想花费很多时间和精力来解决这个问题,可能是唯一可行的方法。第二种方式更好,因为它更通用,但可以根据您的确切需求量身定制,但这是很多工作,而不是轻易跳入。
答案 3 :(得分:2)
可能的解决方案之一是介于1.和2之间。
将池用于小对象:每个对象大小一个池。在这种情况下,您可以通过在数组中存储指针来轻松找到池。
此外,您可以为大型对象提供一个池。在这种情况下,碎片的可能性较小,而且时间开销并不是那么重要,因为大型对象不会经常分配和解除分配。
关于boost::pool
的说明。在测试boost::pool
的性能时,不仅要测试分配,还要测试释放。我经历过boost::pool
和boost::fast_pool
解除分配时间可能非常大。我的案例包括在一个池中分配和取消分配不同大小的小对象
答案 4 :(得分:0)
我对您正在考虑的内存管理器没有具体经验,但这里有一些可能有用的一般指导原则:
通过使用多个池进行开发,您可以充分利用这两个方面(假设速度相似),但是使用单个池进行最终测试和生产发布。这样,您可以在开发期间发现分配/管理问题,但仍然可以从可能更高效的单一池中受益。
答案 5 :(得分:0)
实际上,我会选择2.我可以从linux内核给你一个例子。在内核中,dentry(目录条目)和inode对象应该在内存中缓存更长时间,以便更好地响应用户。由于inode对象依赖于文件系统,因此每个文件系统都将创建自己的对象池。如果对象相似,您可以做的另一件事是抽象出对象并在一个抽象对象中保留公共属性,并使用容器存储对象特定信息。请参阅以下代码以获取完整的想法。