为什么Android下的注释性能问题(慢)?

我是ORMLite的主要作者,它在类上使用Java注释来构build数据库模式。 对于我们的包来说,一个很大的启动性能问题就是Android 1.6下的注释方法的调用。 我看到相同的行为通过3.0。

我们看到,以下简单的注释代码非常令人难以置信 ,是一个真正的性能问题。 在快速的Android设备上,1000次调用注释方法几乎需要一秒钟的时间。 在我的Macbook Pro上运行相同的代码可以在同一时间做28百万(sic)的电话。 我们有一个注释,其中有25个方法,我们想要做超过50秒。

有谁知道这是为什么发生,如果有任何工作? ORMLite在caching这些信息方面可以做些什么,但是有什么我们可以在Android下“修复”注释? 谢谢。

public void testAndroidAnnotations() throws Exception { Field field = Foo.class.getDeclaredField("field"); MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class); long before = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) myAnnotation.foo(); Log.i("test", "in " + (System.currentTimeMillis() - before) + "ms"); } @Target(FIELD) @Retention(RUNTIME) private static @interface MyAnnotation { String foo(); } private static class Foo { @MyAnnotation(foo = "bar") String field; } 

这会导致以下日志输出:

 I/TestRunner( 895): started: testAndroidAnnotations D/dalvikvm( 895): GC freed 6567 objects / 476320 bytes in 85ms D/dalvikvm( 895): GC freed 8951 objects / 599944 bytes in 71ms D/dalvikvm( 895): GC freed 7721 objects / 524576 bytes in 68ms D/dalvikvm( 895): GC freed 7709 objects / 523448 bytes in 73ms I/test ( 895): in 854ms 

编辑:

@candrews指出我正确的方向后,我做了一些代码。 性能问题看起来是由一些可怕的Method.equals()代码在Method.equals() 。 它调用两个方法的toString() ,然后比较它们。 每个toString()使用StringBuilder和一堆append方法,没有一个好的初始化大小。 通过比较字段来进行.equals会快得多。

编辑:

一个有趣的反思性能改善给了我。 我们现在使用reflection窥视AnnotationFactory类来直接读取字段列表。 这使得reflection类对我们来说快20 ,因为它绕过了使用method.equals()调用的调用。 这不是一个通用的解决scheme,但这里是来自ORMLite SVN仓库的Java代码。 有关通用解决scheme,请参阅下面的yanchenko的答案 。

谷歌已经承认这个问题,并将其解决为“后蜂窝”

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

所以至less他们知道这个,并且为了将来的某个版本而修改它。

这是一个通用版本的Greyuser931366的想法:

 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; } } 

我已经用4个元素对一个注释进行了基准testing。
毫秒的时间进行10000次迭代获取所有的值或者调用上面的方法:

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

以下是我如何将它集成到DroidParts : https : //github.com/yanchenko/droidparts/commit/93fd1a1d6c76c2f4abf185f92c5c59e285f8bc69 。

为了跟上这一点,在调用注解方法时,这里仍然存在问题。 Candrews上面列出的bug修复了getAnnotation()的慢度,但是由于Method.equals()问题,在注解上调用方法仍然是个问题。

无法findMethod.equals()的错误报告,所以我在这里创build了一个: https : //code.google.com/p/android/issues/detail? id = 37380

编辑:所以我的工作(感谢@Gray的想法),其实很简单。 (这是主干代码,有些caching,这样就省略了)

 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); 

你的里程会根据使用情况而有所不同,但在某些情况下,这个速度比“正确的方式”快15-20倍,

我想如果你设法改变RUNTIME保留策略,它应该不会那么慢。

编辑:我知道,你的项目可能不是一个选项。 也许这更多的是你用这个注解来做什么的问题,而不是一般的糟糕performance。