Invoke Dynamic的Groovy性能问题?

时间:2017-08-22 18:13:01

标签: java groovy jvm invokedynamic

我正在努力确定导致中等大小的Groovy应用程序在生产中执行缓慢的原因。在进行正在运行的应用程序的线程转储时,我看到的奇怪的事情是很多的线程堆栈跟踪如下:

    at java.lang.invoke.MethodHandleNatives.setCallSiteTargetNormal(Native Method)
    at java.lang.invoke.CallSite.setTargetNormal(CallSite.java:258)
    at java.lang.invoke.MutableCallSite.setTarget(MutableCallSite.java:154)
    at org.codehaus.groovy.vmplugin.v7.Selector$MethodSelector.doCallSiteTargetSet(Selector.java:909)
    at org.codehaus.groovy.vmplugin.v7.Selector$MethodSelector.setCallSiteTarget(Selector.java:969)
    at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:228)
    at java.lang.invoke.LambdaForm$DMH/1665404403.invokeStatic_L3IL5_L(LambdaForm$DMH)
    at java.lang.invoke.LambdaForm$BMH/1705072168.reinvoke(LambdaForm$BMH)

我在网上看到一些提及setCallSiteTargetNormal方法相当重量级并在调用时阻止所有JVM线程。我们使用Groovy的invoke动态支持,我想知道我们是否在Groovy中遇到某种错误,导致这种方法被广泛调用。

我已经检查了明显的性能问题:

  • 内存使用情况良好
  • GC开销正常
  • 服务器上的CPU使用率看起来不错
  • 外部数据库和Web服务调用都正常

关于CPU使用率的一个注意事项是应用程序表现得像是缺乏CPU,但它只使用了大约4 CPU机器总CPU的1/4。它的行为就像一个线程应该是100%的CPU,但我根本没有看到它。但是,我在网上发现的一些信息指向setCallSiTeTargetNormal方法调用是完全阻塞JVM上所有线程的东西。

1 个答案:

答案 0 :(得分:0)

让我提出另一种setCallSiTeTargetNormal方法的替代方案。在这样的问题中,我会检查GC日志,以查看它是否经常进入以清理Permgen(适用于Java 7及之前)或Metaspace(适用于Java 8及更高版本)。如果为其指定限制,则会自动清除元空间,而对于Permgen,您需要在命令行中使用某些开关。

当用于在正在运行的JVM中执行脚本时,Groovy会大量使用此类空间,以便为每个脚本实例化类加载器。然后,当它达到极限时,GC必须清洁它。例如,这是我使用Jenkins时的情况。因此,使用Metaspace就好像它是某种堆,具有相同的行为。每次GC扫描都应该停止你的应用程序,导致明显的停止,而不是击中CPU等。

您应该能够通过使用此命令行来测试并放弃这个想法,以启动您的应用程序,并查看GC完成扫描的频率(以及停止时间有多长)。

-XX:+PrintGC -XX:+PrintGCTimeStamps -Xloggc:/my/log/file