为什么java.lang.Object.getClass()(和反射)比平常慢?

时间:2013-01-09 09:41:31

标签: java reflection jvm jvm-hotspot

我们遇到了一些奇怪的JVM性能问题。

我们有一个大而有些不透明的GUI组件(Actuate Formula 1电子表格)。

如果我们从Event Dispatch Thread初始化所有这些(就像你应该的那样),我们发现代码的运行速度要慢得多(拖动鼠标选择单元格,有明显的滞后)。

如果我们第一次在主启动器线程中初始化它,然后才开始在EDT中使用它,它运行得更快。

当我查看为什么它使用分析器缓慢执行时,所有时间都在进行的方法调用是:

  • java.lang.Object.getClass()
  • java.lang.reflect.Array.newInstance(Class,int)
  • java.lang.Class.getComponentType()
  • java.lang.Thread.currentThread()

我们在Windows 7上使用64位Sun Hotspot JVM(JDK附带的JVM)。

有没有人知道为什么上述方法的执行速度会比平常慢得多?

我在想,也许它与加载类的顺序有关......这是一个合理的理论吗?有没有人知道我可以诊断为什么这些方法调用可能需要很长时间的其他方式?

我已经从探查器附加了两个截图。在两者中,我所做的只是在分析器运行时将鼠标拖动到电子表格单元格周围。所以它只是更新GUI组件而没有做太多其他事情。

第一个是在名为“releaseLock()”的方法中花费大量时间。出于某种原因,这需要很长时间,因为“getComponentType()”比平常花费的时间要长很多。

releaseLock

第二个是在我做了“hack”以消除“releaseLock()”的成本之后 - 但是由于getClass()和currentThread()占用了很多,现在它只花了很多时间在“getLock()”中比平常更久:

getLock

但重要的是,如果我只是简单地改变了代码初始化的顺序,那么这些代码都不需要很长时间才能执行(它甚至根本不会出现在探查器中)。

如果我要优化getLock(),应用程序的执行速度会慢得多。问题实际上似乎是像getClass()这样的方法花费的时间太长了。没有办法弥补这一点 - 在很多地方调用getClass()!

即使没有运行探查器,性能差异也很明显。

还请记住,我们无法更改任何此代码 - 它是一个外部组件。挑战在于解释为什么代码在某些情况下执行速度比其他代码慢得多。

1 个答案:

答案 0 :(得分:1)

你可以尝试在加载下对应用程序进行几次混合(java + native)jstack -m线程转储。

这可能会对Object.getClass()

引擎盖下发生的事情提供一些提示

另见If profiler is not the answer, what other choices do we have?

另请查看What does thread dump looks like when JVM spent time in GC。因为通常的JVM线程转储可能并不总是完全准确,因为它们仅在safepoints上发生。