2017-08-26 62 views
3

我有一个使用Nashorn的应用程序。就我的例子而言,我创建了一个ScriptContext,通过执行一些Javascript来创建一些全局变量,然后通过在紧密循环中调用NashornScriptEngine#eval(String, ScriptContext)在单个线程中反复使用该上下文。我不会将结果存储在任何地方,只要我可以告诉我的应用程序代码不会导致任何副作用。为什么只有使用CMS垃圾回收器时,JVM才会减速?

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

我也经常测试一起扔掉NashornScriptEngine实例和ScriptContext,完全从头开始。此时,我的应用程序没有引用前一次执行的任何变量。这不会改善这些性能问题。

任何想法是怎么回事?我需要与-XX:+UseConcMarkSweepGC一起运行,因为这只是一个较大的长期应用程序的一小部分。

我从下面的Java Mission Control(从飞行记录器获取)中有一些截图。

谢谢!

Heap Reference Objects Top Growers

在这里,我摘走2个选区,一个从记录的开始,一个从终点。请注意“JNI弱参考”时间与“GC暂停”一样是如何显着增加的。

GC At Beginning GC At End

+0

如果这是一个CMS唯一的问题,你有没有试过G1?另外,哪个java版本?我认为CMS只开始使用java8进行类卸载。 – the8472

回答

0

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

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

+0

看着任务控制,加载类保持平坦,所以我不认为这是问题。我会试一试'-XX:+ ParallelRefProcEnabled'。 – swqnzd

+0

ParallelRefProcEnabled似乎已经减少了时间,但问题显然仍然存在 - 从一开始每GC的1ms增加到一小时后每GC的70ms。 – swqnzd

3

有一个bug https://bugs.openjdk.java.net/browse/JDK-8177098。 您可以尝试解决方法 - 每次重新创建NashornScriptEngineFactory?

+0

我曾尝试每隔1,000,000次迭代(2分钟)重新创建NashornScriptEngineFactory,但这似乎没有帮助。我不得不怀疑,这个bug的解决方法恰恰是减慢了它的速度,以至于他没有看到问题(因为创建引擎比eval()更昂贵)。 – swqnzd

+0

@swqnzd(*只是猜测*)也许与https://bugs.openjdk.java.net/browse/JDK-8176454有关?如果GC没有真正起作用,那么放弃工厂也无能为力。如果这是一个静态问题,那么可以使用一个单独的类加载器来解决它,但是对于本机内存来说,只有一个新进程可以提供帮助(如果不传递太多数据,那么创建新进程可能值得一试)。 – maaartinus