Android: combien de frais généraux est généré en exécutant une méthode vide?

J'ai créé une classe pour gérer mes sorties de débogage afin que je n'ai pas besoin de supprimer toutes mes sorties de journal avant la version.

public class Debug { public static void debug( String module, String message) { if( Release.DEBUG ) Log.d(module, message); } } 

Après avoir lu une autre question, j'ai appris que le contenu de l'instruction if n'est pas compilé si le Release.DEBUG constant est faux.

Ce que je veux savoir, c'est la quantité de frais généraux générée par l'exécution de cette méthode vide? (Une fois que la clause if est supprimée, il n'y a plus de code dans la méthode) Est-ce que cela aura un impact sur ma demande? Évidemment, la performance est un gros problème lors de l'écriture pour les combinés mobiles = P

Merci

Gary

5 Solutions collect form web for “Android: combien de frais généraux est généré en exécutant une méthode vide?”

Mesures effectuées sur Nexus S avec Android 2.3.2:

 10^6 iterations of 1000 calls to an empty static void function: 21s <==> 21ns/call 10^6 iterations of 1000 calls to an empty non-static void function: 65s <==> 65ns/call 10^6 iterations of 500 calls to an empty static void function: 3.5s <==> 7ns/call 10^6 iterations of 500 calls to an empty non-static void function: 28s <==> 56ns/call 10^6 iterations of 100 calls to an empty static void function: 2.4s <==> 24ns/call 10^6 iterations of 100 calls to an empty non-static void function: 2.9s <==> 29ns/call 

contrôle:

 10^6 iterations of an empty loop: 41ms <==> 41ns/iteration 10^7 iterations of an empty loop: 560ms <==> 56ns/iteration 10^9 iterations of an empty loop: 9300ms <==> 9.3ns/iteration 

J'ai répété plusieurs fois les mesures. Aucun écart important n'a été trouvé. Vous pouvez voir que le coût par appel peut varier considérablement en fonction de la charge de travail (probablement en raison de la compilation JIT), mais 3 conclusions peuvent être tirées:

  1. Dalvik / java suce d'optimiser le code mort

  2. Les appels de fonction statique peuvent être optimisés beaucoup mieux que non statiques (les fonctions non statiques sont virtuelles et doivent être recherchées dans une table virtuelle)

  3. Le coût sur nexus s n'est pas supérieur à 70ns / call (c'est-à-dire ~ 70 cycles de processeur) et est comparable au coût d'un itinéraire vide pour une itération (c.-à-d. Un incrément et une vérification de condition sur une variable locale)

Observez que dans votre cas, l'argument de chaîne sera toujours évalué. Si vous faites une concaténation de chaîne, cela impliquera la création de chaînes intermédiaires. Cela sera très coûteux et impliquera beaucoup de gc. Par exemple, l'exécution d'une fonction:

 void empty(String string){ } 

Appelé avec des arguments tels que

 empty("Hello " + 42 + " this is a string " + count ); 

10 ^ 4 itérations de 100 appels nécessitent 10 s. C'est 10us / call, c'est-à-dire ~ 1000 fois plus lent qu'un simple appel vide. Il produit également une énorme quantité d'activité GC. La seule façon d'éviter cela est d'insérer manuellement la fonction, c'est-à-dire d'utiliser l'instruction << if << à la place de l'appel de la fonction de débogage. C'est moche mais la seule façon de le faire fonctionner.

Sauf si vous appelez cela dans une boucle profondément imbriquée, je ne m'en soucierais pas.

Un bon compilateur supprime toute la méthode vide, ce qui ne génère aucun frais généraux. Je ne sais pas si le compilateur Dalvik le fait déjà, mais je soupçonne qu'il est probable, du moins depuis l'arrivée du compilateur Just-in-Time avec Froyo.

Voir aussi: Expansion en ligne

En termes de performances, les frais généraux générant les messages qui passent dans la fonction de débogage vont être beaucoup plus sérieux car il est probable qu'ils effectuent des allocations de mémoire, par exemple

 Debug.debug(mymodule, "My error message" + myerrorcode); 

Ce qui se produira même lorsque le message est terminé. Malheureusement, vous avez vraiment besoin de "if (Release.DEBUG)" autour des appels à cette fonction plutôt que dans la fonction elle-même si votre objectif est la performance, et vous verrez cela dans beaucoup de code Android.

C'est une question intéressante et j'aime l'analyse @misiu_mp, alors j'ai pensé que je devrais le mettre à jour avec un test 2016 sur un Nexus 7 exécutant Android 6.0.1. Voici le code de test:

 public void runSpeedTest() { long startTime; long[] times = new long[100000]; long[] staticTimes = new long[100000]; for (int i = 0; i < times.length; i++) { startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyMethod(); } times[i] = (System.nanoTime() - startTime) / 1000; startTime = System.nanoTime(); for (int j = 0; j < 1000; j++) { emptyStaticMethod(); } staticTimes[i] = (System.nanoTime() - startTime) / 1000; } int timesSum = 0; for (int i = 0; i < times.length; i++) { timesSum += times[i]; Log.d("status", "time," + times[i]); sleep(); } int timesStaticSum = 0; for (int i = 0; i < times.length; i++) { timesStaticSum += staticTimes[i]; Log.d("status", "statictime," + staticTimes[i]); sleep(); } sleep(); Log.d("status", "final speed = " + (timesSum / times.length)); Log.d("status", "final static speed = " + (timesStaticSum / times.length)); } private void sleep() { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void emptyMethod() { } private static void emptyStaticMethod() { } 

Le sleep() été ajouté pour empêcher le débordement du tampon Log.d

J'ai joué avec beaucoup de fois et les résultats étaient assez cohérents avec @misiu_mp:

 10^5 iterations of 1000 calls to an empty static void function: 29ns/call 10^5 iterations of 1000 calls to an empty non-static void function: 34ns/call 

L'appel de la méthode statique était toujours légèrement plus rapide que l'appel de la méthode non statique, mais il semblerait que a) l'écart s'est bien fermé depuis Android 2.3.2 et b) il y a encore un coût pour faire des appels à une méthode vide, statique ou ne pas.

En ce qui concerne un histogramme de fois, il révèle quelque chose d'intéressant. La majorité des appels, qu'ils soient statiques ou non, prennent entre 30-40ns, et en regardant attentivement les données, ils sont pratiquement tous les 30ns exactement.

Entrez la description de l'image ici

L'exécution du même code avec des boucles vides (commentant les appels de méthode) produit une vitesse moyenne de 8ns, cependant, environ 3/4 des temps mesurés sont 0ns tandis que le reste est exactement de 30ns.

Je ne suis pas sûr de comment comptabiliser ces données, mais je ne suis pas certain que les conclusions de @issiu_mp tiennent encore. La différence entre les méthodes statiques statiques et non statiques est négligeable et la prépondérance des mesures est exactement de 30ns. Cela étant dit, il semble qu'il y ait encore un coût non nul pour exécuter des méthodes vides.

coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.