我正在努力确定导致中等大小的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中遇到某种错误,导致这种方法被广泛调用。
我已经检查了明显的性能问题:
关于CPU使用率的一个注意事项是应用程序表现得像是缺乏CPU,但它只使用了大约4 CPU机器总CPU的1/4。它的行为就像一个线程应该是100%的CPU,但我根本没有看到它。但是,我在网上发现的一些信息指向setCallSiTeTargetNormal
方法调用是完全阻塞JVM上所有线程的东西。
答案 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