小方法的性能偏差

sve*_*eri 6 java reflection performance osgi

我们有一个OSGi容器,里面有很多产品,其中一个是我们的产品.
我们正在运行一些性能测试,并且存在一个奇怪的问题,即每个OSGi容器重启都会导致我们的一些测试的性能偏差高达400%.
通过一些测试和事情,我能够跟踪这个方法:

public static Method getMethodForSlotKey(Class<?> cls, String slotKey, String methodType) {

    Method[] methods = cls.getMethods();

    if (methods != null && methods.length > 0) {
        for (Method method : methods) {
            String methName = method.getName();
            if (methName.startsWith(methodType)) {

                IDataAnnotation annot = method.getAnnotation(IDataAnnotation.class);
                if (annot != null) {
                    String annotSlotKey = annot.SlotKey();
                    if (annotSlotKey != null && annotSlotKey.equals(slotKey)) {
                        Class<?>[] paramTypes = method.getParameterTypes();
                        // for now, check length == 1 for setter and 0 for getter.
                        int len = SET_TXT.equals(methodType) ? 1 : 0;
                        if (paramTypes != null && paramTypes.length == len) {
                            return method;
                        }
                    }
                }
            }
        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

该方法主要进行反射和字符串比较.

现在,我所做的是缓存此方法的结果,立即我们的偏差降至10 - 20%.当然,这种方法经常被调用,因此有很明显的改进.

我仍然不明白为什么非缓存版本有这么高的偏差,唯一的区别是OSGi/JVM重启?重启期间究竟会发生什么?例如,对于不同的类加载器是否存在任何已知的性能问题?是否有可能在OSGi环境中,库将在重新启动之间以不同的顺序加载?

我在这里寻找一条线索,这是有道理的.

UPDATE

原来这个电话:

Method[] methods = cls.getMethods();
Run Code Online (Sandbox Code Playgroud)

导致偏差.我仍然不明白,所以如果有人这么做,我会很高兴听到它.

J R*_*ape 0

我怀疑这是因为您重新启动服务器/OSGi 容器正在清除Method[]您正在询问的类中的缓存*。缓存将被清除,以确保在重新加载的类具有与同名的旧类不同的公共 API(即不同的方法)的情况下正确操作(例如,如果您加载较新的版本,则可能会发生这种情况)

当您实现“包装器”方法的缓存时,您就规避了这一点并引入了一个假设 - 重新加载的类将具有与先前加载的同名类相同的方法。对于大多数情况来说,这可能是一个相当安全的假设,但不是您希望核心 Java 做出的假设。

Class(OpenJDK)类的源代码在这里。如果你仔细查看它,你会发现getMethods()调用privateGetPublicMethods(). 如果缓存的publicMethodsarray* 为 null,或者由 设为 null clearCachesOnClassRedfinition(),则该类将必须经历相对密集的过程,查找该类中的所有公共方法以及它继承的任何超类和它实现的接口。然后将其缓存,速度getMethods()将恢复正常。


*严格来说,缓存的值是对数组的软引用。