Java方法花了很多时间我无法解释

时间:2013-03-17 03:49:36

标签: java performance reflection jprofiler

使用JProfiler,我发现我的Java代码中有一个我无法理解的热点。 JProfiler解释说这种方法平均需要150μs(674μs,没有预热),不包括调用后代方法所需的时间。 150μs可能看起来不多,但在这个应用程序中,它加起来(并且我的用户经验丰富)并且看起来也很多,相比之下看起来比我更复杂的其他方法。因此对我很重要。

private boolean assertReadAuthorizationForFields(Object entity, Object[] state,
        String[] propertyNames) {
    boolean changed = false;
    final List<Field> fields = FieldUtil.getAppropriatePropertyFields(entity, propertyNames);
    // average of 14 fields to iterate over
    for (final Field field : fields) {
        // manager.getAuthorization returns an enum type
        // manager is a field referencing another component
        if (manager.getAuthorization(READ, field).isDenied()) {
            FieldUtil.resetField(field.getName(), state, propertyNames);
            changed = true;
        }
    }
    return changed;
}

我自己在不同的方向上最小化了这种方法,但它从未教会我很多用处。我不能强调JProfiler报告的持续时间(150μs)仅仅是关于此方法中的代码,并且不包括执行getAuthorizationisDeniedresetField等所需的时间。这也是我开始时只是发布这个片段而没有太多上下文的原因,因为问题似乎与此代码有关,而不是后续的后代方法调用。

也许你可以争论为什么 - 如果你觉得我看到了鬼魂:)无论如何,谢谢你的时间!

3 个答案:

答案 0 :(得分:1)

可能减慢你速度的候选人行为:

  • 主要影响:显然是迭代。如果你有很多领域......你说平均14分,这是非常重要的
  • 主要影响:热点内联意味着被调用的方法包含在您的时代 - 这可能是显而易见的,因为您的方法调用使用反射。 getAppropriatePropertyFields对类字段定义元数据的内省; resetField动态调用setter方法(可能使用Method.invoke()??)。如果你渴望性能,可以通过HashSet使用缓存(映射ElementClass-&gt; FieldMetadataAndMethodHandle)这可能包含setter方法的字段元数据和MethodHandles(而不是使用method.invoke,这很慢)。然后,您只能在应用程序启动期间进行反映,并使用JVM的快速dynamicInvoke支持。
  • 次要影响 - 但乘以迭代次数:如果你有状态和属性名称的非常​​大的数组,并且它们使用原始字段,那么它们将在方法调用期间涉及某种程度的复制(方法参数传递 - ' value'实际上意味着通过引用传递/通过原语传递)

答案 1 :(得分:0)

我建议你自己计算方法,因为探查器并不总能提供准确的计时。

使用此代码创建一个微基准,并将其计时至少2秒。要计算方法调用的差异程度,请将它们注释掉并对它们返回的值进行硬编码。

答案 2 :(得分:0)

我认为问题在于FieldUtil正在使用Reflection并且不会缓存它正在使用的字段。