J'ai remarqué que j'ai toujours utilisé int et double, peu importe la taille du nombre. Donc, en Java, est-il plus efficace d'utiliser byte
ou à la short
place de int
et à la float
place de double
?
Supposons donc que j'ai un programme avec beaucoup d'entiers et de doubles. Cela vaudrait-il la peine de passer en revue et de changer mes entiers en octets ou en short si je savais que le nombre conviendrait?
Je sais que java n'a pas de types non signés, mais y a-t-il quelque chose de plus que je pourrais faire si je savais que le nombre serait uniquement positif?
Par efficace, j'entends principalement le traitement. Je suppose que le ramasse-miettes serait beaucoup plus rapide si toutes les variables avaient la moitié de la taille et que les calculs seraient probablement un peu plus rapides aussi. (Je suppose que depuis que je travaille sur Android, je dois aussi m'inquiéter pour la RAM)
(Je suppose que le garbage collector ne traite que des objets et non des primitifs, mais supprime toujours toutes les primitives des objets abandonnés, n'est-ce pas?)
Je l'ai essayé avec une petite application Android que j'ai mais je n'ai pas vraiment remarqué de différence. (Bien que je n'ai rien mesuré "scientifiquement".)
Ai-je tort de supposer que cela devrait être plus rapide et plus efficace? Je détesterais 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 lorsque je démarre un nouveau projet? (Je veux dire, je pense que chaque petit geste aiderait, mais encore une fois, si c'est le cas, pourquoi ne semble-t-il pas que quelqu'un le fasse.)
la source
Cela dépend de l'implémentation de la JVM, ainsi que du matériel sous-jacent. La plupart du matériel moderne n'extraira pas un octet de la mémoire (ou même du cache de premier niveau), c'est-à-dire que l'utilisation de types primitifs plus petits ne réduit généralement pas la consommation de bande passante mémoire. De même, les processeurs modernes ont une taille de mot de 64 bits. Ils peuvent effectuer des opérations sur moins de bits, mais cela fonctionne en supprimant 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 de la mémoire plus compacte, notamment lors de l'utilisation de tableaux. Cela économise de la mémoire, ce qui peut améliorer la localité de référence (réduisant ainsi le nombre d'erreurs de cache) et réduire la surcharge du garbage collection.
Cependant, de manière générale, l'utilisation des types primitifs plus petits n'est pas plus rapide.
Pour le démontrer, voici le repère suivant:
qui imprime sur mon cahier un peu vieux (en ajoutant des espaces pour ajuster les colonnes):
Comme vous pouvez le voir, les différences de performances sont assez mineures. L'optimisation des algorithmes est bien plus importante que le choix du type primitif.
la source
short
et ilsbyte
sont plus efficaces lorsqu'ils sont stockés dans des tableaux suffisamment grands pour compter (plus le tableau est grand, plus la différence d'efficacité est grande; abyte[2]
pourrait être plus ou moins efficace qu'unint[2]
, mais pas suffisamment pour avoir de l'importance dans les deux cas), mais que les valeurs individuelles sont stockées plus efficacement sous forme deint
.L'utilisation
byte
au lieu deint
peut augmenter les performances si vous les utilisez en grande quantité. Voici une expérience:}
Cette classe teste la vitesse de création d'un nouveau fichier
TestClass
. Chaque test le fait 20 millions de fois et il y a 50 tests.Voici la TestClass:
J'ai dirigé la
SpeedTest
classe et à la fin j'ai ceci:Maintenant, je change les entiers en octets dans TestClass et je l'exécute à nouveau. Voici le résultat:
Je crois que cette expérience montre que si vous instanciez une énorme quantité de variables, utiliser byte au lieu de int peut augmenter l'efficacité
la source
byte
pourrait être >> plus lent << queint
.byte est généralement considéré comme 8 bits. short est généralement considéré comme 16 bits.
Dans un environnement "pur", qui n'est pas java car toutes les implémentations d'octets et de longs, et les courts-circuits et autres choses amusantes vous sont généralement cachés, byte fait un meilleur usage de l'espace.
Cependant, votre ordinateur n'est probablement pas 8 bits, et probablement pas 16 bits. cela signifie que pour obtenir 16 ou 8 bits en particulier, il lui faudrait recourir à la «supercherie» qui fait perdre du temps pour prétendre avoir la capacité d'accéder à ces types en cas de besoin.
À ce stade, cela dépend de la façon dont le matériel est mis en œuvre. Cependant, d'après ce que j'ai appris, la meilleure vitesse est obtenue en stockant des choses en morceaux qui sont confortables pour votre CPU à utiliser. Un processeur 64 bits aime traiter des éléments 64 bits, et rien de moins que cela nécessite souvent de la "magie d'ingénierie" pour faire semblant de les aimer.
la source
L'une des raisons pour lesquelles short / byte / char est moins performant est le manque de prise en charge directe de ces types de données. Par support direct, cela signifie que les spécifications JVM ne mentionnent aucun jeu d'instructions pour ces types de données. Les instructions telles que stocker, charger, ajouter, etc. ont des versions pour le type de données int. Mais ils n'ont pas de versions pour short / byte / char. Par exemple, considérez ci-dessous le code java:
La même chose est convertie en code machine comme ci-dessous.
Maintenant, envisagez de changer int en short comme ci-dessous.
Le code machine correspondant change comme suit:
Comme vous pouvez le constater, pour manipuler un type de données court, il utilise toujours la version d'instruction de type de données int et convertit explicitement int en short lorsque cela est nécessaire. Maintenant, à cause de cela, les performances sont réduites.
Maintenant, la raison invoquée pour ne pas donner de soutien direct est la suivante:
Extrait de la spécification JVM présente ici (Page 58).
la source
javac
compilateur et vous ne pouvez en tirer aucune conclusion fiable sur les performances du programme dans la vie réelle. Le compilateur JIT compile ces bytecodes en instructions machine natives réelles , et effectue une optimisation assez sérieuse dans le processus. Si vous souhaitez analyser les performances du code, vous devez examiner les instructions du code natif. (Et c'est compliqué car vous devez prendre en compte le comportement de synchronisation d'un pipeline x86_64 à plusieurs étages.)La différence est à peine perceptible! C'est plus une question de design, de pertinence, d'uniformité, d'habitude, etc ... Parfois c'est juste une question de goût. Lorsque tout ce qui vous importe, c'est que votre programme soit opérationnel et que le remplacement d'un
float
par unint
ne nuirait pas à l'exactitude, je ne vois aucun avantage à opter pour l'un ou l'autre à moins que vous ne puissiez démontrer que l'utilisation de l'un ou l'autre type altère les performances. L'optimisation des performances en fonction de types différents sur 2 ou 3 octets est vraiment la dernière chose dont vous devriez vous soucier; Donald Knuth a dit un jour: "L'optimisation prématurée est la racine de tout mal" (pas sûr que ce soit lui, éditez si vous avez la réponse).la source
float
ne peut pas représenter tous les entiers d'uneint
boîte; et ne peutint
pas non plus représenter une valeur non entière qui lefloat
peut. Autrement dit, alors que toutes les valeurs int sont un sous-ensemble de valeurs longues, un int n'est pas un sous-ensemble d'un float et un float n'est pas un sous-ensemble d'un int.substituting a float for a double
, si tel est le cas, le répondeur devrait modifier la réponse. Si ce n'est pas le cas, le répondeur devrait baisser la tête de honte et revenir à l'essentiel pour les raisons exposées par @pst et pour de nombreuses autres raisons.