【发布时间】:2011-11-17 01:28:00
【问题描述】:
我是ORMLite 的主要作者,它在类上使用Java 注释来构建数据库模式。我们的包的一个大的启动性能问题原来是在 Android 1.6 下调用注解方法。我在 3.0 之前看到了相同的行为。
我们看到以下简单的注释代码是难以置信 GC 密集型和真正的性能问题。在快速的 Android 设备上,对注释方法的 1000 次调用几乎需要一秒钟。在我的 Macbook Pro 上运行的相同代码可以同时进行 2800 万次(原文如此)调用。我们有一个注释,其中包含 25 个方法,我们希望每秒执行 50 多个。
有谁知道为什么会发生这种情况以及是否有任何解决方法? ORMLite 在缓存这些信息方面当然可以做一些事情,但是我们可以做些什么来“修复”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() 中的一些糟糕的粗略代码引起的。它正在调用这两种方法的toString(),然后比较它们。每个toString() 都使用StringBuilder 和一堆没有良好初始化大小的附加方法。通过比较字段来执行.equals 会明显更快。
编辑:
给我一个有趣的反射性能改进。我们现在使用反射来窥视AnnotationFactory 类,以直接读取字段列表。这使反射类对我们来说快了 20 倍,因为它绕过了使用 method.equals() 调用的调用。这不是一个通用的解决方案,但这里是来自ORMLite SVN repository 的 Java 代码。有关通用解决方案,请参阅yanchenko's answer below。
【问题讨论】:
-
如果您对
foo属性使用int而不是String,您会看到类似的时间安排吗?可能是字符串池的问题? -
与
int或任何其他类型同时使用。这是关于注释而不是它们注释的内容。 Tnx。 -
@Gray 根据candrews referenced 的问题以及该答案的cmets 中引用的问题,此问题已得到修复。您知道删除
ORMLite config file的Android 版本是安全的吗?
标签: java android performance garbage-collection annotations