【问题标题】:Handling heavy load on the GC with Scala Case Classes使用 Scala 案例类处理 GC 上的繁重负载
【发布时间】: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


    【解决方案1】:

    为了减轻 Full GC 的痛苦,我建议使用 G1 或 CMS 而不是并行收集器,并增加年轻空间以减少提升到终身空间的对象数量,但没有什么比一开始就减少工作量更好。

    你创建的垃圾越多,你做的工作就越多,gc 清理对象的工作也就越多。使用更多 CPU 更快地创建对象不会减少 GC 的痛苦。

    【讨论】:

    • 实际上,创建大量短暂的不可变对象几乎是现代分代 GC 的最佳案例。甚至在 10 年前,使用 Rich Hickey 在 Clojure 中的 Ant Simulation 就证明了 Azul 的 GC 可以毫不费力地通过 864 核机器上的 700 个并行线程生成的 20 GiByte/s 垃圾。现代的世代 GC 建立在世代假设之上:对象年轻时死去,老对象不引用年轻对象。这正是 FP 所做的:大量的短期对象,没有“时间倒退的引用”。并且没有突变体。
    • @JörgWMittag 25 MB/s/core 对于那台机器来说已经很多了,但现在你的机器生产 1 GB/s/core。调优 gc 最简单的方法就是降低负载。
    • 显然我将致力于限制创建的对象数量,但现在我只想评估这种方法在重负载下的可行性。无论如何,我尝试了 CMS,并使用 jstat 进行了一些观察。结果是 CMS 和默认 GC 之间的帧率只有很小的差异,如果负载太大,两者都无法达到令人满意的性能。尽管如此,我还是学到了很多关于 GC(从来没有用这种方式优化它)和我的代码的知识。关键是,只要我在内存中同时考虑当前和下一个状态,我就会遇到问题。
    • @Chobeat in java 我让分析器指导我优化代码区域。飞行记录器非常适合这一点。我还没有用 Scala 尝试过。
    • 我在使用 VisualVM,但感觉它不是正确的工具。谢谢你的建议,我一定会试试的。
    猜你喜欢
    • 2012-05-28
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多