我正在努力确定是什么导致了一个中等大小的 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 的调用动态支持,我想知道我们是否遇到了 Groovy 中的某种错误,导致该方法被过度调用。
我已经检查过的明显性能问题:
- 内存使用没问题
- GC 开销是正常的
- 服务器上的 CPU 使用率看起来还不错
- 外部数据库和网络服务调用都正常
关于 CPU 使用率的一个注意事项是,该应用程序的行为就像它需要 CPU 一样,但它只使用了 4 CPU 机器的总 CPU 的大约 1/4。它的行为就像一个线程应该 100% 与 CPU 挂钩,但我根本没有看到这一点。然而,我在网上找到的一些信息表明setCallSiTeTargetNormal
方法调用完全阻塞了 JVM 上的所有线程。