【问题标题】:Java garbage collector causes massive lagsJava 垃圾收集器导致大量滞后
【发布时间】:2019-09-14 03:17:43
【问题描述】:

每次,当控制台中出现以下消息时,我都会注意到我的游戏出现了很大的延迟。

[GC (Allocation Failure) 
Desired survivor size 133693440 bytes, new threshold 7 (max 15)
[PSYoungGen: 916500K->130553K(918016K)] 1018868K->444063K(1232384K), 1.2505777 secs] [Times: user=1.87 sys=0.43, real=1.25 secs] 
[Full GC (Ergonomics) [PSYoungGen: 130553K->127049K(918016K)] [ParOldGen: 313509K->314172K(555008K)] 444063K->441222K(1473024K), [Metaspace: 9374K->9374K(1058816K)], 3.7134878 secs]

我使用以下参数运行我的程序:

-Xms1024M
-Xmx2048M
-XstartOnFirstThread
-XX:+PrintGCDetails
-XX:+PrintClassHistogram
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime

有没有可能减少 GC 所需的时间?如何查看 GC 收集的对象的类?

【问题讨论】:

  • 哪个JVM版本?您使用的是哪个 GC(G1?)?您分配了多少总堆内存? (在最后一个上,我看到你在那里列出了它。)
  • 当您看到这些 GC 事件时,您必须进行分析并捕获多个堆转储。分析这些转储并查看导致内存泄漏的最大对象。然后您可以修改代码以修复泄漏。
  • 对于如此小的堆大小来说,这些令人费解的高暂停。同样奇怪的是,在一个年轻的 gc 已经回收了足够多的内存之后,JVM 执行了一个毫无意义的完整 gc。也许,对于这么小的堆,使用并行 gc 弊大于利。但无论如何,由于您似乎在 Java 8 或更高版本下运行,只需尝试不同的 gc 算法,例如G1.
  • 谢谢。是的,你是对的,我使用 Java 8。使用更高版本的 Java 会有什么不同吗?我曾尝试使用 G1,但它并没有带来任何明显的改进。我认为,我的代码中存在导致问题的任何问题,我必须像@RahulVedpathak 建议的那样解决问题。
  • 当我们不知道问题的真正原因时,很难说不同的 Java 版本是否会改变任何东西。我猜,这个问题可能与 JVM 完全无关,是由交换等平台问题引起的。

标签: java garbage-collection


【解决方案1】:

减少垃圾收集时间的最有效方法是减少垃圾量。

您可以使用 JvisualVM 之类的分析器(JDK 附带)来准确查看您的程序如何使用分配的内存以及垃圾收集花费了多少时间。

在游戏程序的情况下,您希望获得一致的帧速率:您需要重构代码,以便尽可能多地重复使用对象,而不是创建新对象并允许它们将在以后收集(当不可避免地需要垃圾收集时,这将导致明显的滞后峰值)。 (不幸的是,这就是为什么像 Java 这样的内存管理语言并不是特别适合游戏的原因。)

【讨论】:

  • 我发现我总是在我的代码中创建 Vector 类的新实例。是否有可能在每个类中拥有一个或两个静态字段,以便这些向量能够重用它们?
  • @DasElias 可能——是的;但就功能准确性而言,我建议您打开一个单独的问题,提供更详细的答案。
猜你喜欢
  • 2011-11-07
  • 1970-01-01
  • 1970-01-01
  • 2020-11-05
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
相关资源
最近更新 更多