java - GC 应用程序运行缓慢后

java - after GC application runs slow

我有一个 运行JVM 上的应用程序(游戏)。

游戏的更新逻辑(运行s 60 times/s)结束时使用了大约 25% "time-slice"(1/60s),然后休眠剩余的 75% .但是当 GC 收集器达到 运行 时,它会上升到 75-200% 并在执行的其余部分保持在那里。

该游戏使用了大约 70Mb 的堆,并以大约 1-2mb/s 的速度增长。当 GC 为 运行 时,它会回到 70Mb,因此没有真正的内存泄漏。以后我会尽量降低这个数字,但在这个范围内应该问题不大。

我使用的 JVM 8 没有 运行时间参数或标志,不确定哪个 GC 会给我。

我已经尝试将堆设置为不同的大小,但它不会影响这种现象。

关于为什么会这样,我有两种理论:

  1. GC 无意中以一种导致更新循环中缓存垃圾的方式对我的堆进行碎片化。我的逻辑在循环遍历并更新数据时从数据邻近性中受益匪浅。会不会是把一些数据shuffle到old area,而把一些数据留在young(the nursery)?

  2. 突然的 GC 处理触发了我的 OS,让它意识到我的主要更新步骤不需要像目前那样多的 CPU 资源,降低了它的优先级. (但是,即使我跳过 thread.sleep() 以关闭未使用的 CPU 用法,这种现象仍然存在。

你怎么看。我的理论是否合理,是否可以对其进行任何处理,或者我是否需要切换到 C 语言?我对 GC 的了解有限。

P.S。作为旁注,通常 update() 完成 75% post GC。当我使用 VSync 时,我得到了 200% 这样的数字。

What do you think. Are my theories plausible,

第一种理论是合理的,但第二种理论则不然。

can anything be done about them

您可以通过以下方式改进:

  1. 增加最大堆大小。
  2. 切换到低暂停收集器。
  3. 性能优化基于分析应用程序的结果
  4. 正在努力降低垃圾产生率。

or do I need to switch to C or C++?

C 和 C++ 会为您提供更可预测的行为,因为没有任何东西可以移动对象。如果您具备适当的技能并付出努力,您应该 能够在 C 和 C++ 中获得更好的性能,尤其是在进行图形/渲染时。然而,那些是大 "if"s。

不再有效:

我做了一个测试,完全毁了我的架构。我有这个,这是应用程序的瓶颈:

class Physics{
   Vec2 centre;
   Rec hitbox;
   Vec2 speed;
   Vec2 acc;
   ...

   public void update(){ //critical method
       centre.doThings();
       hitbox.doThings();
       etc...
   }

}

并将其更改为仅使用原语:

class Physics{
   double centreX,centreY;
   double x1,x2,y1,y2;
   double speedX,speedY;
   double accX,accY;
   ...

   public void update(){ //critical method
       implementation of methods above...
       etc...
   }

}

这是因为,至少,java 保证 class 原始成员按照声明的顺序存储在堆上的 class header 之下.虽然对 objects 的引用可能是堆另一端的地址。

这与压缩 GC 一起给了我一个很好的提升,我认为这是缓存命中率的增加。它摧毁了我的架构,但这是我愿意付出的代价。

现在游戏稳定运行在15%,现在我把自己的post标记为答案

编辑: 那只是一个糊涂人的胡言乱语。以上只给了我一个小的性能提升 - 其余的是由于应用程序中的错误,因此不能证明体系结构更改的合理性。不过,压缩 GC 有所帮助。