为什么Android下的注解会出现这样的性能问题(慢)? [英] Why are annotations under Android such a performance issue (slow)?

查看:32
本文介绍了为什么Android下的注解会出现这样的性能问题(慢)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 ORMLite 的主要作者,它在类上使用 Java 注释来构建数据库模式.我们的包的一个很大的启动性能问题是在 Android 1.6 下调用注释方法.我在 3.0 之前看到了相同的行为.

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 calling of annotation methods under Android 1.6. I see the same behavior up through 3.0.

我们看到以下简单的注释代码难以置信 GC 密集型和一个真正的性能问题.在快速的 Android 设备上调用 1000 次注释方法几乎需要一秒钟.在我的 Macbook Pro 上运行的相同代码可以同时进行 2800 万次(原文如此)调用.我们有一个包含 25 个方法的注释,我们希望每秒执行 50 个以上的方法.

We are seeing that the following simple annotation code is incredibly GC intensive and a real performance problem. 1000 calls to an annotation method takes almost a second on a fast Android device. The same code running on my Macbook Pro can do 28 million (sic) calls in the same time. We have an annotation that has 25 methods in it and we'd like to do more than 50 of these a second.

有谁知道为什么会发生这种情况以及是否有任何解决方法?在缓存这些信息方面,ORMLite 当然可以做一些事情,但是我们可以做些什么来修复"Android 下的注释?谢谢.

Does anyone know why this is happening and if there is any work around? There are certainly things that ORMLite can do in terms of caching this information but is there anything that we can do to "fix" annotations under Android? Thanks.

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

这会导致以下日志输出:

This results in the following log output:

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 会明显更快.

After @candrews pointed me in the right direction, I did some poking around the code. The performance problem looks to be caused by some terrible, gross code in Method.equals(). It is calling the toString() of both methods and then comparing them. Each toString() use StringBuilder with a bunch of append methods without a good initializing size. Doing the .equals by comparing fields would be significantly faster.

我得到了一个有趣的反射性能改进.我们现在使用反射来查看 AnnotationFactory 类的内部,以直接读取字段列表.这使反射类对我们来说快了 20 ,因为它绕过了使用 method.equals() 调用的调用.这不是一个通用的解决方案,但这里的 Java 代码来自 ORMLite SVN 存储库.有关通用解决方案,请参阅yanchenko 在下面的回答.

An interesting reflection performance improvement was given to me. We are now using reflection to peek inside the AnnotationFactory class to read the list of fields directly. This makes the reflection class 20 times faster for us since it bypasses the invoke which is using the method.equals() call. It is not a generic solution but here's the Java code from ORMLite SVN repository. For a generic solution, see yanchenko's answer below.

推荐答案

Google 已承认该问题并在蜂巢之后"进行了修复

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

https://code.google.com/p/android/问题/详细信息?id=7811

所以至少他们知道它并且据说已经在未来的某个版本中修复了它.

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

这篇关于为什么Android下的注解会出现这样的性能问题(慢)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆