Devriez-vous minimiser la création d'un grand nombre de petits objets?

10

Lorsque vous écrivez souvent quelque chose qui crée de nombreux (des milliers) de petits objets, devriez-vous essayer de le minimiser pour les performances? Surtout si vous ne savez pas sur quel système il sera exécuté, des ordinateurs de bureau bas à haut de gamme ou même mobiles. Pour le mobile, j'ai entendu dire que la création de nombreux objets entrave considérablement les performances, bien que je ne sache pas à quel point cela est vrai.

J'ai un exemple qui montre bien cette idée. Dans un programme graphique, supposons qu'il existe une méthode utilisée pour tous les dessins, idéalement appelée drawPixel(Point). Il pourrait y avoir des milliers de points créés et il peut être répété souvent, comme dans un jeu où il pourrait être appelé plus de 60 fois par seconde. Alternativement, drawPixel(int x, int y)pourrait être utilisé pour minimiser la création de nombreux objets Point.

Dans une conception orientée objet, je pense que l'utilisation de Point serait préférable. Cependant, l'utilisation de types primitifs peut augmenter les performances. Le gain de performances peut être négligeable dans la plupart des cas, mais je ne suis pas sûr de choses comme des machines mobiles ou plus anciennes. Quel est le gain de performances de faire quelque chose comme ça et est-ce quelque chose qui devrait être pris en considération?

Stripies
la source
J'ai du mal à trouver des références pour sauvegarder cela, mais en général, dans Java 8, ne vous inquiétez pas. Ne faites pas de choses évidemment stupides, mais si vous n'êtes pas délibérément un gaspillage, le système devrait fonctionner très bien. Sun / Oracle ont eu environ 20 ans pour régler le GC et la gestion de la mémoire et ils sont vraiment bons dans ce domaine.
@Snowman J'ai entendu dire que les nouvelles versions de Java améliorent la gestion de la mémoire, mais le problème que je vois est qu'il n'y a aucune garantie que l'utilisateur n'utilise pas une ancienne version. C'est en partie ce qui a créé ma préoccupation.
Stripies
1
Faites d'abord une mesure du rendement. Si vous avez des problèmes, réfléchissez à l'optimisation. Mais ne sacrifiez pas la maintenabilité du code trop tôt car vous pensez que vous pourriez avoir des problèmes de performances.
Repéré le
2
@Stripies Performances des objets Java de courte durée déjà répondu dans Faut-il éviter la création d'objets en Java? . Cependant, si vous devez gérer des centaines de millions de ces objets par seconde, ce n'est qu'à ce moment-là que vous devez reconsidérer ce problème.
rwong
1
Si vous vous inquiétez des anciennes versions de Java, vérifiez-les lors de l'installation. Une machine virtuelle Java assez ancienne pour causer un problème de gestion de la mémoire, a également beaucoup de problèmes de sécurité bien connus, donc inciter les utilisateurs à mettre à jour leur fait une faveur. System.getProperty("java.version")(ou "java.vm.version") est un point de départ.
Jerry Coffin du

Réponses:

17

En général, non , vous ne devez pas éviter de créer des objets par crainte d'une perte de performances. Il y a plusieurs raisons à cela.

  1. L'utilisation d'objets est en quelque sorte l'intérêt d'utiliser Java. Les éviter de manière préventive est un signe que la décision d'utiliser Java n'était peut-être pas la bonne au départ.
  2. Les problèmes de performance sont notoirement difficiles à prévoir. Ne présumez jamais que quelque chose est un goulot d'étranglement. Mesurez toujours . L'ingénierie de la performance consiste presque toujours à effectuer de petits changements exactement au bon endroit. Vous ne pouvez pas prédire le bon endroit sans mesurer plus que vous ne pouvez prédire l'effet d'un médicament sans expérience.
  3. Le coût de création d'objet est largement surestimé. Dans une machine virtuelle Java moderne, cela revient essentiellement à incrémenter un pointeur (et avec les récupérateurs de génération, le coût de sa gestion est également négligeable). Il y a beaucoup de textes sur Internet qui vous conseillent d'éviter les objets, d'utiliser le pool d'objets, etc. Ce conseil était parfois juste dans les années 1990; aujourd'hui, il est surtout obsolète. Il est très peu probable que vous obteniez suffisamment de performances pour justifier le coût de développement et la complexité supplémentaires introduits en évitant les objets ou en les gérant vous-même.

Cela dit, il y a des endroits où transformer quelque chose en objet n'a pas de sens pour commencer. Le passage de deux coordonnées à une routine de dessin pourrait être un tel cas: la paire de coordonnées n'a pas d'existence indépendante, elle n'a pas d'identité, elle n'est utilisée qu'une seule fois puis immédiatement rejetée, etc.

Si tel est le cas, alors bien sûr, allez-y et passez deux ints plutôt que de les envelopper dans un objet. Le but de la POO n'est pas que tout doit être un objet. Le fait est que les objets facilitent le développement là où ils sont la solution naturelle à un problème de représentation des données. N'évitez pas les objets là où ils ont du sens - ne les présentez pas là où ils ne le font pas.

Kilian Foth
la source
2

Lorsque vous envisagez des impacts sur les performances avant d'avoir écrit du code, vous devez supposer que vous ne savez pas ce que vous faites.

Il y a un très petit espace pour les objets en java par rapport aux primitives. Plus vos objets sont minuscules, plus le pourcentage de surcharge sera élevé. Cependant, j'ai appris depuis longtemps que les choses qui doublent n ne sont rien par rapport aux choses qui multiplient n par n.

Donc, alors que oui, vous pouvez imaginer un système qui a eu la moitié de l'impact sur la taille ou même un quatrième, veuillez vous demander pourquoi vous vous souciez vraiment. Les solutions compliquées à ce problème ne seront pas bien reçues. En particulier parce que plonger dans un tel code sera source de confusion. Les programmeurs confus écrivent du mauvais code. Ils écrivent n fois n code qui devrait être n log n code. Et ils prennent plus de temps pour le faire.

Maintenant, si vous pouvez me faire gagner de l'espace avec une astuce qui tient dans une belle boîte que je n'ai pas à regarder la plupart du temps, nous pouvons parler. Si c'est une boîte, je peux l'échanger contre une autre boîte quand cette boîte fonctionnerait mieux, je peux même la payer.

candied_orange
la source
2

Dans l'optimisation des performances que j'ai effectuée ( exemple ), il est très facile pour la gestion de la mémoire d'être un coupable majeur. Peu m'importe combien ils ont réglé le nouvel opérateur et le garbage collector, le calcul le plus rapide n'est pas un calcul. Donc, si je trouve que le gestionnaire de mémoire prend un bon pourcentage de temps et que je ne peux pas éviter de créer des objets , je trouve un moyen de les réutiliser, plutôt que d'en créer constamment de nouveaux.

Je ne fais cela que si je dois fabriquer des objets. Pour les graphiques, généralement pas. À mon humble avis, les graphiques doivent être dessinés , pas construits . Bien sûr, vous pourriez dire qu'une image se compose de points, de lignes qui les relient, de polygones, de texte, etc. Cela ne signifie pas que vous n'avez pas d'autre choix que d'en faire des objets avant de les dessiner . Je les dessine juste.

Il y a une méthode Paint. Je remplace cela, dessine tout sur une image bitmap, puis bloque le transfert à l'écran. Cela semble instantané. Pour la saisie de la souris, il existe des méthodes pour remplacer, pour détecter les clics, les glissements, etc.

La POO est une bonne idée pour certaines raisons. Ces raisons ne s'appliquent pas dans toutes les situations.

Mike Dunlavey
la source
Je suis d'accord, mais je suis également d'accord avec tout le monde que le test est le seul moyen de savoir avec certitude. Assurez-vous que vous avez des spécifications qui le font de manière simple / évidente avant de l'optimiser ... mais je suis d'accord que le nouveau peut toujours être un problème.
Bill K
2

Allez-y et utilisez de petites allocations. Les gestionnaires de mémoire modernes, en particulier le gestionnaire d'objets Java hautement optimisé, sont extrêmement efficaces. Enregistrer une optimisation des performances majeure pour un programme de travail.

Il est extrêmement probable que les performances globales soient adéquates. Si vous trouvez que ce n'est pas le cas, alors, et alors seulement , profilez les performances du code. Au cours d'une longue carrière dans le développement de logiciels, j'ai appris que les goulots d'étranglement ne sont presque jamais là où vous vous attendez.

Un jour, un membre de l'équipe a passé plusieurs jours à accélérer la recherche de membres d'objet 20 fois plus rapidement. Succès! Cependant, la meilleure accélération globale en utilisation réelle a été mesurée en centièmes de pour cent. La modification a été immédiatement annulée, car l'accélération nécessitait des allocations de mémoire par membre plus importantes.

Bill Ferguson
la source
1

C'est simple: si vous avez besoin de 1000 petits objets, vous créez 1000 petits objets et ne vous en faites pas. Si vous avez besoin de 100 petits objets, alors créer 1000 petits objets est stupide - créez ceux dont vous avez besoin et pas plus.

Si vous êtes préoccupé par les performances (et si vous ne vous inquiétez pas non plus des performances), toutes les fonctionnalités doivent être écrites une seule fois au même endroit, ce qui rend l'ensemble de votre code plus simple et plus facile à comprendre. Ensuite, si vous avez un problème de performances, la mesure peut vous montrer qu'il y a un endroit où le problème de performances se produit, ce qui facilite les choses, et un seul endroit où vous devez le changer. Ou la mesure montre que cet endroit ne pose aucun problème, alors vous avez terminé.

gnasher729
la source