【发布时间】:2017-01-20 05:16:26
【问题描述】:
我正在游戏中使用 Scala 开发模拟。我想只使用不可变对象来定义游戏逻辑,即使它效率低下。为什么?因为我能,所以我会。
现在我要强调一下主游戏循环,因为它会以巨大的负载推动模拟。基本上我有这些嵌套的案例类,并且我使用 .copy() 来定义模拟中给定实体的以下状态。问题是所有这些操作都会生成大量未引用的对象,因此在每一步结束时,我都会触发 Full GC。这对游戏性能不利。
所以我开始了一些积极的优化:首先现在模拟步骤在游戏后面并行运行,计算基本上涵盖游戏一天的“下一个状态”。因此,在计算下一天时,将向玩家显示当天的状态。这是有效的,因为基本上游戏中的每个主要实体(基本上是城市)都被假定为孤立地发展。如果某个代理(玩家或其他在城市之间穿梭的 AI 代理)会接触到城市,我会根据代理操作的动作重新计算“下一个状态”。无论如何,这与现在无关。
所以我让这些平行实体在幕后进化,当一天结束时(一天被定义为世界地图中玩家的 5 步),我使用 Await.result(nextWorldState, 5 seconds) 作为集合点来更新当前模拟的状态。这不一定是游戏应该如何运行,但我想在游戏的其余部分等待计算下一个状态时测试一个集合点,因为这可能是必要的。
我的问题是,在此之后,我一次取消引用很多对象,这会触发 GC 收集。我尝试了一些解决方案,但是当我访问 Future 的结果并用它替换当前状态时总会有一点,这总是会触发 GC。
假设我不想参加常规课程(可能我会)并假设我不想将状态拆分为多个部分并分别处理它们(我会尝试这个,但它看起来无法维护),有什么聪明的办法解决这个问题吗?
以下是处理此逻辑的实际函数中的一些非伪代码:
class WorldSimulationManager(var worldState: WorldState) {
private var nextWorldState: Future[WorldState] =
Future.successful(worldState)
def doImmutableStep(gameMap:GameMap,movedCountToday:Int):Unit = {
nextWorldState =
nextWorldState.flatMap(_.doStep(gameMap))
if (movedCountToday >= Constants.tileMovementsToDay) {
worldState = Await.result(nextWorldState, 5 seconds)
}
}
}
【问题讨论】:
标签: java scala garbage-collection case-class