[Performance] En java, est-il plus efficace d'utiliser byte ou short au lieu de int et float au lieu de double?


Answers

Cela dépend de l'implémentation de la JVM, ainsi que du matériel sous-jacent. Le matériel le plus moderne ne récupérera pas les octets uniques de la mémoire (ou même du cache de premier niveau), c'est-à-dire que l'utilisation des types primitifs plus petits ne réduit généralement pas la consommation de bande passante mémoire. De même, les CPU modernes ont une taille de mot de 64 bits. Ils peuvent effectuer des opérations sur moins de bits, mais cela fonctionne en rejetant les bits supplémentaires, ce qui n'est pas plus rapide non plus.

Le seul avantage est que les types primitifs plus petits peuvent entraîner une disposition mémoire plus compacte, notamment lors de l'utilisation de tableaux. Cela économise de la mémoire, ce qui peut améliorer la localisation de référence (réduisant ainsi le nombre d'échecs de cache) et réduire les frais généraux de récupération de place.

D'une manière générale, cependant, l'utilisation des types primitifs plus petits n'est pas plus rapide.

Pour le démontrer, voici le benchmark suivant:

package tools.bench;

import java.math.BigDecimal;

public abstract class Benchmark {

    final String name;

    public Benchmark(String name) {
        this.name = name;
    }

    abstract int run(int iterations) throws Throwable;

    private BigDecimal time() {
        try {
            int nextI = 1;
            int i;
            long duration;
            do {
                i = nextI;
                long start = System.nanoTime();
                run(i);
                duration = System.nanoTime() - start;
                nextI = (i << 1) | 1; 
            } while (duration < 100000000 && nextI > 0);
            return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }   

    @Override
    public String toString() {
        return name + "\t" + time() + " ns";
    }

    public static void main(String[] args) throws Exception {
        Benchmark[] benchmarks = {
            new Benchmark("int multiplication") {
                @Override int run(int iterations) throws Throwable {
                    int x = 1;
                    for (int i = 0; i < iterations; i++) {
                        x *= 3;
                    }
                    return x;
                }
            },
            new Benchmark("short multiplication") {                   
                @Override int run(int iterations) throws Throwable {
                    short x = 0;
                    for (int i = 0; i < iterations; i++) {
                        x *= 3;
                    }
                    return x;
                }
            },
            new Benchmark("byte multiplication") {                   
                @Override int run(int iterations) throws Throwable {
                    byte x = 0;
                    for (int i = 0; i < iterations; i++) {
                        x *= 3;
                    }
                    return x;
                }
            },
            new Benchmark("int[] traversal") {                   
                @Override int run(int iterations) throws Throwable {
                    int[] x = new int[iterations];
                    for (int i = 0; i < iterations; i++) {
                        x[i] = i;
                    }
                    return x[x[0]];
                }
            },
            new Benchmark("short[] traversal") {                   
                @Override int run(int iterations) throws Throwable {
                    short[] x = new short[iterations];
                    for (int i = 0; i < iterations; i++) {
                        x[i] = (short) i;
                    }
                    return x[x[0]];
                }
            },
            new Benchmark("byte[] traversal") {                   
                @Override int run(int iterations) throws Throwable {
                    byte[] x = new byte[iterations];
                    for (int i = 0; i < iterations; i++) {
                        x[i] = (byte) i;
                    }
                    return x[x[0]];
                }
            },
        };
        for (Benchmark bm : benchmarks) {
            System.out.println(bm);
        }
    }
}

qui imprime sur mon cahier un peu vieux:

int multiplication  1.530 ns
short multiplication    2.105 ns
byte multiplication 2.483 ns
int[] traversal 5.347 ns
short[] traversal   4.760 ns
byte[] traversal    2.064 ns

Comme vous pouvez le voir, les différences de performance sont assez mineures. L'optimisation des algorithmes est beaucoup plus importante que le choix du type primitif.

Question

J'ai remarqué que j'ai toujours utilisé les int et les doubles, peu importe leur taille. Donc, en java, est-il plus efficace d'utiliser byte ou short au lieu de int et float au lieu de double?

Supposons donc que j'ai un programme avec beaucoup d'ints et de doubles. Cela vaudrait-il la peine de passer et de changer mes ints en octets ou en shorts si je savais que le nombre conviendrait?

Je sais que Java n'a pas de types non signés mais y at-il quelque chose de plus que je pourrais faire si je savais que le nombre serait positif seulement?

Par efficace, je veux dire principalement le traitement. Je suppose que le ramasse-miettes serait beaucoup plus rapide si toutes les variables étaient de la moitié de la taille et que les calculs seraient probablement un peu plus rapides aussi. (Je suppose que puisque je travaille sur Android, je dois aussi m'inquiéter un peu de ram)

(Je suppose que le garbage collector ne traite que des objets et non des primitives mais supprime quand même toutes les primitives dans les objets abandonnés?)

Je l'ai essayé avec une petite application Android, mais je n'ai pas vraiment remarqué de différence du tout. (Bien que je n'ai pas "scientifiquement" mesuré quoi que ce soit.)

Ai-je tort de supposer que cela devrait être plus rapide et plus efficace? Je détesterais passer à travers et tout changer dans un programme massif pour découvrir que j'ai perdu mon temps.

Cela vaudrait-il la peine de le faire dès le début d'un nouveau projet? (Je veux dire, je pense que chaque petit geste serait utile, mais encore une fois si oui, pourquoi ne semble-t-il pas que quelqu'un le fait.)

Merci beaucoup. C'est juste un problème que j'ai réfléchi.




octet est généralement considéré comme 8 bits. court est généralement considéré comme 16 bits.

Dans un environnement "pur", qui n'est pas java comme toutes les implémentations d'octets et de longs, de courts métrages, et d'autres choses amusantes vous sont généralement cachées, l'octet fait un meilleur usage de l'espace.

Cependant, votre ordinateur n'est probablement pas 8 bits, et ce n'est probablement pas 16 bits. cela signifie que pour obtenir 16 ou 8 bits en particulier, il faudrait recourir à la "supercherie" qui gaspille du temps pour prétendre avoir la possibilité d'accéder à ces types en cas de besoin.

À ce stade, cela dépend de la façon dont le matériel est implémenté. Cependant, d'après ce qu'on m'a dit, la meilleure vitesse est obtenue en stockant des choses en morceaux qui sont confortables pour votre CPU. Un processeur 64 bits aime traiter avec des éléments 64 bits, et tout ce qui est inférieur à cela nécessite souvent une «magie d'ingénierie» pour prétendre qu'il aime traiter avec eux.