Why are annotations under Android such a performance issue (slow)?

前端 未结 4 523
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-02 05:56

I\'m the lead author of ORMLite which uses Java annotations on classes to build database schemas. A big startup performance problem for our package turns out to be the call

相关标签:
4条回答
  • 2020-12-02 05:58

    Here's a generic version of Gray's & user931366's idea:

    public class AnnotationElementsReader {
    
        private static Field elementsField;
        private static Field nameField;
        private static Method validateValueMethod;
    
        public static HashMap<String, Object> getElements(Annotation annotation)
                throws Exception {
            HashMap<String, Object> map = new HashMap<String, Object>();
            InvocationHandler handler = Proxy.getInvocationHandler(annotation);
            if (elementsField == null) {
                elementsField = handler.getClass().getDeclaredField("elements");
                elementsField.setAccessible(true);
            }
            Object[] annotationMembers = (Object[]) elementsField.get(handler);
            for (Object annotationMember : annotationMembers) {
                if (nameField == null) {
                    Class<?> cl = annotationMember.getClass();
                    nameField = cl.getDeclaredField("name");
                    nameField.setAccessible(true);
                    validateValueMethod = cl.getDeclaredMethod("validateValue");
                    validateValueMethod.setAccessible(true);
                }
                String name = (String) nameField.get(annotationMember);
                Object val = validateValueMethod.invoke(annotationMember);
                map.put(name, val);
            }
            return map;
        }
    
    }
    

    I've benchmarked an annotation with 4 elements.
    Millisecond times for 10000 iterations of either getting values of all of them or calling the method above:

         Device        Default  Hack
    HTC Desire 2.3.7    11094   730
    Emulator 4.0.4      3157    528
    Galaxy Nexus 4.3    1248    392
    

    Here's how I've integrated it into DroidParts: https://github.com/yanchenko/droidparts/commit/93fd1a1d6c76c2f4abf185f92c5c59e285f8bc69.

    0 讨论(0)
  • 2020-12-02 05:58

    To follow up on this, there's still a problem here when calling methods on annotations. The bug listed above by candrews fixes the getAnnotation() slowness, but calling a method on the annotation is still a problem due to the Method.equals() issues.

    Couldn't find a bug report for Method.equals() so I created one here: https://code.google.com/p/android/issues/detail?id=37380

    Edit: So my work around for this (thanks for the ideas @Gray), is actually pretty simple. (this is trunkcated code, some caching and such is omitted)

    annotationFactory = Class.forName("org.apache.harmony.lang.annotation.AnnotationFactory");
    getElementDesc = annotationFactory.getMethod("getElementsDescription", Class.class);
    Object[] members = (Object[])getElementDesc.invoke(annotationFactory, clz); // these are AnnotationMember[]
    
    Object element = null;
    for (Object e:members){ // AnnotationMembers
        Field f = e.getClass().getDeclaredField("name");
        f.setAccessible(true);
        String fname = (String) f.get(e);
        if (methodName.equals(fname)){
            element = e;
        break;
        }
    }
    
    if (element == null) throw new Exception("Element was not found");
    Method m = element.getClass().getMethod("validateValue");
    return m.invoke(element, args);
    

    You mileage will vary based on use, but in may case this was about 15-20 times faster then doing it the "right way"

    0 讨论(0)
  • 2020-12-02 06:02

    I think if you manage to change the RUNTIME retention policy, it should not be that slow.

    EDIT: I know, for your project that may not be an option. Perhaps it is more a problem of what you are doing with that annotation rather than bad performance in general.

    0 讨论(0)
  • 2020-12-02 06:08

    Google has acknowledged the issue and fixed it "post-Honeycomb"

    https://code.google.com/p/android/issues/detail?id=7811

    So at least they know about it and have supposedly fixed it for some future version.

    0 讨论(0)
提交回复
热议问题