【问题标题】:Why does the JVM slow down over time only when using the CMS garbage collector?为什么只有在使用 CMS 垃圾收集器时 JVM 才会随着时间变慢?
【发布时间】:2017-08-26 02:50:37
【问题描述】:

我有一个使用 Nashorn 的应用程序。出于我的示例的目的,我创建了一个 ScriptContext,我通过执行一些 Javascript 来创建一些全局变量,然后通过在紧密循环中调用 NashornScriptEngine#eval(String, ScriptContext) 在单个线程中一遍又一遍地使用该上下文。我不会将结果存储在任何地方,据我所知,我的应用程序代码不会造成任何副作用。

使用默认的 GC 可以无限期地正常工作。但是当我使用-XX:+UseConcMarkSweepGC 运行相同的应用程序时,性能会随着时间的推移而显着下降。程序启动时,运行 1,000,000 次迭代大约需要 2 分钟。但 2 小时后,同样的 1,000,000 次迭代大约需要 4 分钟。从那里开始变得更糟。

我还测试了定期丢弃 NashornScriptEngine 实例和 ScriptContext,完全重新开始。那时,我的应用程序没有引用上一次执行中的任何变量。这并不能改善这些性能问题。

知道发生了什么吗?我需要使用-XX:+UseConcMarkSweepGC 运行,因为这只是一个较大的长期应用程序的一小部分。

我有一些来自下面 Java Mission Control 的屏幕截图(取自 Flight Recorder)。

谢谢!

这里我选择了两个 GC,一个从录音的开头,一个从结尾。请注意“JNI 弱引用”时间是如何显着增加的,“GC 暂停”也是如此。

【问题讨论】:

  • 如果这是仅 CMS 的问题,您是否尝试过 G1?另外,哪个java版本?我认为CMS默认情况下才开始使用java8进行类卸载。

标签: java performance garbage-collection jvm nashorn


【解决方案1】:

有一个错误https://bugs.openjdk.java.net/browse/JDK-8177098。 您能否尝试解决方法 - 每次都重新创建 NashornScriptEngineFactory?

【讨论】:

  • 我确实尝试每 1,000,000 次迭代(2 分钟)重新创建 NashornScriptEngineFactory,但这似乎没有帮助。我不得不怀疑该错误中的解决方法是否恰好减慢了它的速度,以至于他没有看到问题(因为创建引擎比eval()ing 更昂贵)。
  • @swqnzd (只是猜测) 也许与bugs.openjdk.java.net/browse/JDK-8176454有关?如果 GC 真的不起作用,那么放弃工厂也无济于事。如果是某些静态问题,那么可以使用单独的类加载器来解决它,但是对于本机内存,只有一个新进程可以提供帮助(如果您不传达太多数据,那么创建新进程可能值得一试)。
【解决方案2】:

正如您自己指出的,它在 JNI 引用处理上花费了大量时间。默认情况下这是单线程的。设置-XX:+ParallelRefProcEnabled让它并行运行。

由于您使用的是动态生成字节码的 nashorn 引擎,因此也可能是类卸载或缺少类的问题,但这在您的日志中并不明显。

【讨论】:

  • 查看任务控制,加载的类保持相当平稳,所以我认为这不是问题。我会试试-XX:+ParallelRefProcEnabled
  • ParallelRefProcEnabled 似乎减少了时间,但问题显然仍然存在 - 从开始时的每次 GC 1 毫秒增加到一小时后每次 GC 的 70 毫秒。
猜你喜欢
  • 1970-01-01
  • 2011-02-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
  • 2016-10-14
  • 1970-01-01
相关资源
最近更新 更多