Je suis l'auteur principal de ORMLite qui utilise des annotations Java sur les classes de construire des schémas de base de données. Un gros problème de performances de démarrage pour notre forfait s'avère être l'appel de l'annotation méthodes sous Android 1.6. Je vois le même comportement jusqu'à 3.0.
Nous constatons que le simple suivant l'annotation de code est incroyablement GC intensif et un réel problème de performance. 1000 appels à une annotation méthode prend près d'une seconde sur un rapide de la boîte. Le même code fonctionne sur mon Mac Pro 28 millions de dollars (sic) appels en même temps. Nous avons une annotation qui a 25 méthodes et nous aimerions faire plus de 50 de ces une seconde.
Personne ne sait pourquoi ce qui se passe et si il n'y a aucune contourner? Il y a certainement des choses que ORMLite peut faire en termes de mise en cache de cette information, mais il n'y a rien que nous pouvons faire pour "réparer" les annotations sous Android? Merci.
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;
}
Cette résultats dans la suite de la sortie du journal:
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
EDIT:
Après @candrews m'a orienté dans la bonne direction, j'ai fait un peu de fouiller le code. Le problème semble être causé par quelque terrible, brut code en Method.equals()
. C'est l'appel de la toString()
des deux méthodes et de les comparer. Chaque toString()
utilisation StringBuilder
avec un tas d'ajouter des méthodes sans une bonne initialisation de la taille. Faire l' .equals
en comparant les champs seraient nettement plus rapide.
EDIT:
Une réflexion intéressante d'amélioration de la performance m'a été donné. Nous sommes maintenant à l'aide de la réflexion de jeter un regard à l'intérieur de l' AnnotationFactory
classe de lire la liste des champs directement. Cela rend la réflexion de la classe 20 fois plus rapide pour nous, car il évite de l'appeler, qui est l'aide de l' method.equals()
appel. Ce n'est pas une solution générique, mais voici le code Java à partir de ORMLite dépôt SVN. Pour une solution générique, voir yanchenko la réponse ci-dessous.