343 votes

L’impact sur les performances de l’utilisation d’instanceof en Java

Je suis en train de travailler sur une application et une approche de conception implique de très forte utilisation de l'opérateur instanceof. Même si je sais que OO conception essaie généralement d'éviter d'utiliser instanceof, c'est une autre histoire, et cette question est purement liées à la performance. Je me demandais si il n'y a aucun impact sur les performances? Est aussi rapide que l' ==?

Par exemple, j'ai une classe de base avec 10 sous-classes. En une seule fonction qui prend la classe de base, je ne vérifie si la classe est une instance de la sous-classe et de réaliser une certaine routine.

L'un des autres façons j'ai pensé à la résolution qu'il a été d'utiliser un "id de type" integer primitive au lieu de cela, et d'utiliser un masque de bits pour représenter les catégories de la sous-classes, et puis il suffit de faire un peu de masque de comparaison des sous-classes de type "id" à une constante masque représentant la catégorie.

Est instanceof d'une certaine manière optimisée par la JVM pour être plus rapide que ça? Je veux m'en tenir à Java, mais la performance de l'application est critique. Ce serait cool si quelqu'un qui a été dans cette voie avant que pourrait vous offrir quelques conseils. Je suis tatillonne trop ou en se concentrant sur la mauvaise chose à optimiser?

289voto

Steve Points 1491

Les compilateurs JVM / JIC modernes ont supprimé les performances de la plupart des opérations traditionnellement «lentes», notamment instanceof, gestion des exceptions, réflexion, etc.

Comme Donald Knuth l'a écrit: «Nous devrions oublier les petites efficacités, disons environ 97% du temps: l'optimisation prématurée est la racine de tous les maux. La performance de instanceof ne sera probablement pas un problème, alors ne perdez pas votre temps à trouver des solutions de contournement exotiques jusqu'à ce que vous soyez sûr que c'est le problème.

20voto

brianegge Points 12857

Les éléments qui permettront de déterminer l'impact de la performance sont:

  1. Le nombre de classes possibles pour lesquelles l'opérateur instanceof pourrait retourner true
  2. La distribution de vos données sont la plupart du instanceof opérations résolu dans la première ou la deuxième tentative? Vous aurez envie de mettre vos plus susceptibles de retourner vrai opérations en premier.
  3. L'environnement de déploiement. En cours d'exécution sur un Sun Solaris VM est significativement différente de celle de Sun JVM Windows. Solaris sera exécuté dans le mode 'serveur' par défaut, alors que Windows exécute en mode client. Le JIT optimisations sur Solaris, fera tous les accès de méthode mesure la même.

J'ai créé un microbenchmark pour les quatre différentes méthodes d'expédition. Les résultats de Solaris sont comme suit, avec le plus petit nombre étant plus rapide:

InstanceOf 3156
class== 2925 
OO 3083 
Id 3067

19voto

Olaf Kock Points 18072

Pour répondre à votre dernière question: à Moins d'un profileur vous dit, que vous dépenser des quantités ridicules de temps dans un instanceof: Oui, vous êtes tatillon.

Avant de se demander à propos de l'optimisation de quelque chose qui n'aurait jamais dû être optimisé: Écrire un algorithme dans le plus lisible et de l'exécuter. L'exécuter, jusqu'à ce que le jit-compilateur obtient une chance pour l'optimiser. Ensuite, si vous avez des problèmes avec ce morceau de code, utiliser un profiler pour vous dire, où pour gagner le plus et de les optimiser.

En temps de très optimisation des compilateurs, vos suppositions sur les goulots d'étranglement seront susceptibles d'être complètement mauvais.

Et dans le véritable esprit de cette réponse (qui je wholeheartly crois): je ne suis absolument pas savoir comment instanceof et == concernent une fois le jit-compilateur a une chance pour l'optimiser.

J'ai oublié: ne mesurez Jamais la première manche.

16voto

Xtra Coder Points 446

J'ai la même question, mais parce que je n'ai pas trouvé de 'métriques de performance' pour un cas d'utilisation similaire au mien, j'ai fait quelques exemples de code. Sur mon matériel et Java 6 & 7, la différence entre instanceof et switch sur les itérations 10mln est

 for 10 child classes - instanceof: 1200ms vs switch: 470ms
for 5 child classes  - instanceof:  375ms vs switch: 204ms
 

Donc, instanceof est vraiment plus lent, surtout sur un grand nombre d'instructions if-else-if, cependant la différence sera négligeable dans l'application réelle.

 import java.util.Date;

public class InstanceOfVsEnum {

    public static int c1, c2, c3, c4, c5, c6, c7, c8, c9, cA;

    public static class Handler {
        public enum Type { Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Type9, TypeA }
        protected Handler(Type type) { this.type = type; }
        public final Type type;

        public static void addHandlerInstanceOf(Handler h) {
            if( h instanceof H1) { c1++; }
            else if( h instanceof H2) { c2++; }
            else if( h instanceof H3) { c3++; }
            else if( h instanceof H4) { c4++; }
            else if( h instanceof H5) { c5++; }
            else if( h instanceof H6) { c6++; }
            else if( h instanceof H7) { c7++; }
            else if( h instanceof H8) { c8++; }
            else if( h instanceof H9) { c9++; }
            else if( h instanceof HA) { cA++; }
        }

        public static void addHandlerSwitch(Handler h) {
            switch( h.type ) {
                case Type1: c1++; break;
                case Type2: c2++; break;
                case Type3: c3++; break;
                case Type4: c4++; break;
                case Type5: c5++; break;
                case Type6: c6++; break;
                case Type7: c7++; break;
                case Type8: c8++; break;
                case Type9: c9++; break;
                case TypeA: cA++; break;
            }
        }
    }

    public static class H1 extends Handler { public H1() { super(Type.Type1); } }
    public static class H2 extends Handler { public H2() { super(Type.Type2); } }
    public static class H3 extends Handler { public H3() { super(Type.Type3); } }
    public static class H4 extends Handler { public H4() { super(Type.Type4); } }
    public static class H5 extends Handler { public H5() { super(Type.Type5); } }
    public static class H6 extends Handler { public H6() { super(Type.Type6); } }
    public static class H7 extends Handler { public H7() { super(Type.Type7); } }
    public static class H8 extends Handler { public H8() { super(Type.Type8); } }
    public static class H9 extends Handler { public H9() { super(Type.Type9); } }
    public static class HA extends Handler { public HA() { super(Type.TypeA); } }

    final static int cCycles = 10000000;

    public static void main(String[] args) {
        H1 h1 = new H1();
        H2 h2 = new H2();
        H3 h3 = new H3();
        H4 h4 = new H4();
        H5 h5 = new H5();
        H6 h6 = new H6();
        H7 h7 = new H7();
        H8 h8 = new H8();
        H9 h9 = new H9();
        HA hA = new HA();

        Date dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerInstanceOf(h1);
            Handler.addHandlerInstanceOf(h2);
            Handler.addHandlerInstanceOf(h3);
            Handler.addHandlerInstanceOf(h4);
            Handler.addHandlerInstanceOf(h5);
            Handler.addHandlerInstanceOf(h6);
            Handler.addHandlerInstanceOf(h7);
            Handler.addHandlerInstanceOf(h8);
            Handler.addHandlerInstanceOf(h9);
            Handler.addHandlerInstanceOf(hA);
        }
        System.out.println("Instance of - " + (new Date().getTime() - dtStart.getTime()));

        dtStart = new Date();
        for( int i = 0; i < cCycles; i++ ) {
            Handler.addHandlerSwitch(h1);
            Handler.addHandlerSwitch(h2);
            Handler.addHandlerSwitch(h3);
            Handler.addHandlerSwitch(h4);
            Handler.addHandlerSwitch(h5);
            Handler.addHandlerSwitch(h6);
            Handler.addHandlerSwitch(h7);
            Handler.addHandlerSwitch(h8);
            Handler.addHandlerSwitch(h9);
            Handler.addHandlerSwitch(hA);
        }
        System.out.println("Switch of - " + (new Date().getTime() - dtStart.getTime()));
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X