Un collègue m'a dit que la création d'objets en Java est l'opération la plus chère que vous puissiez effectuer. Je ne peux donc que conclure à la création du moins d’objets possible.
Cela semble quelque peu contrecarrer le but de la programmation orientée objet. Si nous ne créons pas d'objets, nous n'écrivons qu'un seul style de classe C, pour l'optimisation?
Réponses:
Votre collègue n'a aucune idée de ce dont ils parlent.
Votre opération la plus chère serait de les écouter . Ils vous ont fait perdre votre temps à vous orienter vers des informations obsolètes depuis plus de dix ans (à la date à laquelle cette réponse a été publiée) et à passer du temps à poster ici et à rechercher Internet sur la vérité.
Espérons qu'ils ne font que régurgiter par ignorance quelque chose qu'ils ont entendu ou lu il y a plus de dix ans et qu'ils ne savent pas mieux. Je prendrais également pour suspect tout ce qu'ils ont dit, il devrait s'agir d'une erreur bien connue de quiconque se tient au courant de toute façon.
Tout est un objet (sauf
primitives
)Tous les
int, long, double
objets autres que les primitives ( , etc.) sont des objets en Java. Il n'y a aucun moyen d'éviter la création d'objets en Java.La création d'objets en Java, en raison de ses stratégies d'allocation de mémoire, est plus rapide que le C ++ et, à toutes fins pratiques, par rapport à tout le reste de la machine virtuelle Java, elle peut être considérée comme "libre" .
Au début, comme à la fin des années 1990 et au début des années 2000, l’implémentation réelle d’objets a été légèrement ralentie par l’implémentation de JVM. Cela n’a pas été le cas depuis au moins 2005.
Si vous accordez la prise
-Xms
en charge de toute la mémoire dont vous avez besoin pour que votre application fonctionne correctement, il se peut que le GC ne soit jamais obligé d'exécuter et de balayer la plupart des déchets dans les implémentations modernes du GC. Les programmes de courte durée peuvent ne jamais supporter la GC.Il n'essaie pas d'optimiser l'espace libre, ce qui est un casse-tête de toute façon, il optimise les performances de l'exécution. Si cela signifie que la pile JVM est allouée presque à 100% tout le temps, qu’il en soit ainsi. De toute façon, la mémoire de pile JVM libre ne vous fournit rien.
Il y a une idée fausse que le GC va libérer la mémoire de manière utile au reste du système, c'est complètement faux!
Le segment de mémoire de la machine virtuelle Java ne grossit pas et ne diminue pas, de sorte que le reste du système est affecté positivement par la mémoire disponible dans le segment de mémoire de la machine virtuelle Java .
-Xms
alloue TOUT ce qui est spécifié au démarrage et sa méthode heuristique consiste à ne jamais réellement restituer cette mémoire au système d'exploitation afin de la partager avec tout autre processus du système d'exploitation jusqu'à la fermeture complète de cette instance de la machine virtuelle Java.-Xms=1GB -Xmx=1GB
alloue 1 Go de RAM quel que soit le nombre d'objets créés à un moment donné. Certains paramètres permettent de libérer des pourcentages de la mémoire de tas, mais pour des raisons pratiques, la JVM n'est jamais en mesure de libérer suffisamment de mémoire pour que cela se produise.ainsi, aucun autre processus ne peut récupérer cette mémoire, de sorte que le reste du système ne bénéficie pas non plus de la pile JVM. Un RFE pour cela a été "accepté" le 29-NOV-2006, mais rien n’a été fait à ce sujet. Ce comportement n’est considéré comme une préoccupation par personne d’autorité.Il existe une idée fausse selon laquelle la création de nombreux objets de courte durée entraîne la pause de la machine virtuelle Java pendant de longues périodes. Cette erreur est également fausse.
Les algorithmes actuels du GC sont en fait optimisés pour la création de nombreux petits objets de courte durée. Il s’agit en fait de l’heuristique à 99% pour les objets Java dans chaque programme. Les tentatives de regroupement d’objets vont en réalité ralentir les performances de la machine virtuelle Java dans la plupart des cas.
Les seuls objets qui ont besoin d'être mis en pool aujourd'hui sont les objets qui font référence à des ressources finies externes à la machine virtuelle Java; Les sockets, fichiers, connexions à la base de données, etc. peuvent être réutilisés. Les objets normaux ne peuvent pas être regroupés dans le même sens que dans les langues vous permettant d'accéder directement aux emplacements de mémoire. La mise en cache des objets est un concept différent et peut être ou ne pas être ce que certaines personnes appellent naïvement le pooling . Les deux concepts ne sont pas la même chose et ne doivent pas être confondus.
Les algorithmes GC modernes ne rencontrent pas ce problème car ils ne désallouent pas de manière planifiée, ils le font quand la mémoire disponible est nécessaire pour une génération donnée. Si le tas est suffisamment grand, aucune désallocation ne se produit suffisamment longtemps pour provoquer des pauses.
Les langages dynamiques orientés objet battent le C même aujourd'hui plusieurs jours sur les tests sensibles au calcul.
la source
_alloca
amorties.new
mot clé dans un hotspot. J'ai vu des gens utilisernew ImageIcon(Image)
dans lapaint()
méthode des objets Swing, ce qui est assez coûteux et rendait l'interface utilisateur super lente. Donc, ce n'est pas une réponse en noir et blanc, réfléchissez avant d'utilisernew
quelque part.En bout de ligne: Ne compromettez pas votre conception afin de prendre des raccourcis créant des objets. Évitez de créer des objets inutilement. Si nécessaire, veillez à éviter les opérations redondantes (de quelque nature que ce soit).
Contrairement à la plupart des réponses - oui, l’allocation d’objets a un coût associé. Le coût est faible, mais vous devez éviter de créer des objets inutiles. Même chose que vous devriez éviter rien inutile dans votre code. Les graphiques d'objet volumineux ralentissent le CPG, impliquent des temps d'exécution plus longs, car vous allez probablement avoir plus d'appels de méthode, déclencher plus d'erreurs dans le cache du processeur et augmenter la probabilité que votre processus soit échangé sur le disque dans les cas où la RAM est faible.
Avant que quiconque ne prétende qu'il s'agisse d'un cas limite, j'ai profilé des applications qui, avant d'optimiser, ont créé plus de 20 Mo d'objets afin de traiter environ 50 lignes de données. Cela convient très bien dans les tests, jusqu'à ce que vous augmentiez jusqu'à cent demandes par minute et que vous créiez tout à coup 2 Go de données par minute. Si vous voulez faire 20 requêtes par seconde, vous créez 400 Mo d’objets, puis vous les jetez. 20 reqs / sec est minuscule pour un serveur décent.
la source
while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...
cela. être un gaspillage par exemplebyte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ...
.En fait, en raison des stratégies de gestion de la mémoire rendues possibles par le langage Java (ou tout autre langage géré), la création d’objets n’est guère plus que l’incrémentation d’un pointeur dans un bloc de mémoire appelé jeune génération. C'est beaucoup plus rapide que C, où une recherche de mémoire libre doit être faite.
L'autre partie du coût est la destruction d'objets, mais il est difficile de comparer avec C. Le coût d'une collection est basé sur la quantité d'objets sauvegardés à long terme, mais la fréquence des collections est basée sur la quantité d'objets créés ... dans Au final, il reste beaucoup plus rapide que la gestion de la mémoire de type C.
la source
Point
objet peut tenir dans deux registres à usage général).D'autres afficheurs ont souligné à juste titre que la création d'objets est extrêmement rapide en Java et que vous ne devriez généralement pas vous en soucier dans les applications Java normales.
Il y a quelques situations très particulières où est est une bonne idée d'éviter la création d'objets.
la source
Ce que dit votre collègue contient un noyau de vérité. Je suggère respectueusement la question avec l' objet la création est en fait poubelle collection . En C ++, le programmeur peut contrôler avec précision la libération de la mémoire. Le programme peut accumuler crud aussi longtemps ou aussi peu qu’il le souhaite. De plus, le programme C ++ peut ignorer le crud en utilisant un autre thread que celui qui l'a créé. Ainsi, le thread qui travaille actuellement ne doit jamais s'arrêter pour nettoyer.
En revanche, la machine virtuelle Java (JVM) arrête périodiquement votre code pour récupérer la mémoire inutilisée. La plupart des développeurs Java ne remarquent jamais cette pause, car elle est généralement peu fréquente et très courte. Plus vous accumulez de crud ou plus votre JVM est contrainte, plus ces pauses sont fréquentes. Vous pouvez utiliser des outils tels que VisualVM pour visualiser ce processus.
Dans les versions récentes de Java, l'algorithme de récupération de place (GC) peut être optimisé . En règle générale, plus les pauses sont courtes, plus la surcharge de la machine virtuelle est onéreuse (c.-à-d. Que la CPU et la mémoire ont passé de temps à coordonner le processus du CPG).
Quand est-ce que cela pourrait avoir de l'importance? Chaque fois que vous vous souciez de taux de réponse cohérents inférieurs à une milliseconde, vous vous souciez de GC. Les systèmes de trading automatisés écrits en Java adaptent fortement la machine virtuelle pour minimiser les pauses. Les entreprises qui écriraient autrement Java se tournent vers C ++ dans des situations où les systèmes doivent être très réactifs en permanence.
Pour mémoire, je ne tolère pas l' évitement d'objet en général! Par défaut à la programmation orientée objet. Ajustez cette approche uniquement si le CPG se met en travers de votre chemin, et seulement après avoir tenté d’ajuster la machine virtuelle Java de manière à la suspendre moins longtemps. Java Performance de Charlie Hunt et Binu John est un bon livre sur le réglage des performances Java .
la source
Il y a un cas où vous pouvez être dissuadés de créer trop d'objets en Java à cause de la surcharge - conception optimisée pour la performance sur la plate-forme Android
Autre que cela, les réponses ci-dessus sont vraies.
la source
le GC est réglé pour de nombreux objets éphémères
Cela dit, si vous pouvez réduire de manière triviale l'allocation d'objets, vous devriez
un exemple serait la construction d'une chaîne dans une boucle, la manière naïve serait
qui crée un nouvel
String
objet sur chaque+=
opération (plus unStringBuilder
et le nouveau tableau de caractères sous-jacent)vous pouvez facilement réécrire ceci en:
ce modèle (résultat immuable et une valeur intermédiaire mutable locale) peut être appliqué à d'autres choses aussi
mais à part cela, vous devriez utiliser un profileur pour trouver le véritable goulot d'étranglement au lieu de chasser les fantômes.
la source
StringBuilder
approche est la pré-taille de laStringBuilder
sorte qu'il ne doit réattribuer le tableau sous - jacent avec leStringBuilder(int)
constructeur. Cela en fait une allocation unique plutôt que des1+N
allocations.Joshua Bloch (un des créateurs de la plate-forme Java) a écrit dans son livre Effective Java en 2001:
la source
Cela dépend vraiment de l'application spécifique, donc c'est vraiment difficile à dire en général. Cependant, je serais assez surpris que la création d'objet soit en réalité un goulot d'étranglement dans les performances d'une application. Même s'ils sont lents, les avantages de ce type de code l'emporteront probablement sur les performances (à moins que l'utilisateur ne le remarque réellement)
Dans tous les cas, vous ne devriez même pas vous inquiéter de ces problèmes tant que vous n’avez pas profilé votre code pour déterminer les goulets d’étranglement des performances réelles au lieu de deviner. Jusque-là, vous devriez faire tout ce qui est préférable pour la lisibilité du code, pas pour la performance.
la source
Je pense que votre collègue a dû dire du point de vue de la création d'objet inutile. Je veux dire si vous créez fréquemment le même objet, il est préférable de le partager. Même dans les cas où la création d'objet est complexe et nécessite plus de mémoire, vous pouvez cloner cet objet et éviter de créer ce processus de création d'objet complexe (mais cela dépend de vos besoins). Je pense que la déclaration "La création d'objet coûte cher" devrait être considérée dans son contexte.
En ce qui concerne les exigences en matière de mémoire JVM, attendez Java 8, vous n'avez même pas besoin de spécifier -Xmx, les paramètres de méta-espace prendront en charge les besoins en mémoire de la JVM et ceux-ci augmenteront automatiquement.
la source
Créer une classe ne se résume pas à allouer de la mémoire. Il y a aussi l'initialisation, je ne sais pas pourquoi cette partie n'est pas couverte par toutes les réponses. Les classes normales contiennent des variables et effectuent une certaine forme d'initialisation, ce qui n'est pas gratuit. Selon la classe, la classe peut lire des fichiers ou effectuer un nombre différent d'opérations lentes.
Pensez donc simplement à ce que le constructeur de la classe fait avant de déterminer s'il est gratuit ou non.
la source
Le GC de Java est en fait très optimisé en termes de création rapide et volumineuse d'objets. D'après ce que je peux comprendre, ils utilisent un allocateur séquentiel (l'allocateur O (1) le plus rapide et le plus simple pour les requêtes de taille variable) pour ce type de "cycle rafale" dans un espace mémoire qu'ils appellent "espace Eden", et uniquement si les objets persistent. après un cycle de GC, ils sont déplacés vers un endroit où le GC peut les collecter un par un.
Cela dit, si vos besoins en performances deviennent suffisamment critiques (mesurés avec les exigences réelles des utilisateurs finaux), alors les objets sont vraiment surchargés, mais je n'y penserais pas tellement en termes de création / allocation. Cela concerne davantage la localité de référence et la taille supplémentaire de tous les objets en Java, nécessaires pour prendre en charge des concepts tels que la réflexion et la répartition dynamique (elle
Float
est plus grande quefloat
, souvent environ 4 fois plus grande sur 64 bits avec ses exigences d'alignement, et tableau deFloat
n'est pas nécessairement garanti d'être stocké contigu de ce que je comprends).L’une des choses les plus accrocheuses que j’ai jamais vues développées en Java et qui m’a fait considérer comme un gros concurrent dans mon domaine (VFX) était un traqueur de chemin standard multithread interactif (ne pas utiliser le cache irradiance ni le BDPT ou le MLS ou toute autre chose) sur le processeur fournit des aperçus en temps réel qui convergent assez rapidement vers une image sans bruit. J'ai travaillé avec des professionnels du C ++, consacrant leur carrière à de telles choses avec des profils fantaisistes à la main qui avaient des difficultés à le faire.
Mais j’ai scruté le code source et, bien qu’il utilise beaucoup d’objets à un coût dérisoire, les parties les plus critiques du traceur de chemin (le BVH, les triangles et les matériaux) ont très clairement et délibérément évité les objets au profit de grands réseaux de types primitifs ( généralement
float[]
etint[]
), ce qui lui a fait utiliser beaucoup moins de mémoire et une localité spatiale garantie pour aller d’unfloat
élément du tableau à l’autre. Je ne pense pas que ce soit trop spéculatif de penser que, si l'auteur utilisait des types en boîte aimaitFloat
là-bas, sa performance aurait été très coûteuse. Mais nous parlons de la partie la plus critique de ce moteur, et je suis à peu près sûr, étant donné l’habileté du développeur de l’optimiser, qu’il a mesuré cela et appliqué cette optimisation très, très judicieusement, puisqu’il a utilisé avec bonheur des objets partout ailleurs avec coût insignifiant pour son impressionnant traceur de chemins en temps réel.Même dans un domaine aussi critique que le mien en termes de performances, vous n'écrirez pas des produits efficaces si vous vous bloquez dans des endroits sans importance. J'affirmerais même que les domaines les plus critiques en termes de performances pourraient entraîner une demande de productivité encore plus grande, car nous avons besoin de tout le temps supplémentaire nécessaire pour régler ces points chauds qui importent vraiment en ne perdant pas autant de temps sur des tâches qui ne le sont pas. . Comme avec l'exemple de traçage de chemin ci-dessus, l'auteur a appliqué habilement et judicieusement de telles optimisations uniquement aux endroits qui importaient vraiment, et probablement après coup, après avoir mesuré, et utilisaient toujours avec bonheur des objets partout ailleurs.
la source
float[]
vsFloat[]
, où le traitement séquentiel d'un million d' objets anciens peut être relativement plus rapide que le second.Comme certains l’ont dit, la création d’objets n’est pas très coûteuse en Java (mais je parie que la plupart des opérations simples comme l’ajout, etc.) ne doit pas être évitée de trop.
Cela dit, cela reste un coût, et vous pouvez parfois essayer de supprimer autant d'objets que possible. Mais seulement après que le profilage a montré que c'est un problème.
Voici une excellente présentation sur le sujet: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf
la source
J'ai fait un microbenchmark rapide à ce sujet et j'ai fourni des sources complètes dans github. Ma conclusion est que la question de savoir si la création d'objets est coûteuse ou non n'est pas le problème, mais la création continue d'objets avec la notion que le GC s'occupera de tout, votre application déclenchera plus tôt le processus de GC. Le GC est un processus très coûteux et il est préférable de l’éviter autant que possible et de ne pas essayer de le pousser à s’engager.
la source