Eh bien, il y a plusieurs questions en une seule ici !
1 - Comment sont gérés les objets éphémères ?
Comme indiqué précédemment, la JVM peut parfaitement gérer une grande quantité d'objets de courte durée, puisqu'elle suit le principe de l'utilisation des objets de courte durée. Hypothèse générationnelle faible .
Notez que nous parlons d'objets qui ont atteint la mémoire principale (heap). Ce n'est pas toujours le cas. Beaucoup d'objets que vous créez ne quittent même pas un registre du CPU. Par exemple, considérez ce for-loop
for(int i=0, i<max, i++) {
// stuff that implies i
}
Ne pensons pas au déroulage des boucles (une optimisation que la JVM effectue lourdement sur votre code). Si max
est égal à Integer.MAX_VALUE
votre boucle peut prendre un certain temps à s'exécuter. Cependant, le i
n'échappera jamais au bloc-boucle. Par conséquent, la JVM placera cette variable dans un registre du CPU, l'incrémentera régulièrement mais ne la renverra jamais dans la mémoire principale.
Ainsi, la création de millions d'objets n'est pas un gros problème s'ils ne sont utilisés que localement. Ils seront morts avant d'être stockés dans Eden, donc le GC ne les remarquera même pas.
2 - Est-il utile de réduire l'overhead du GC ?
Comme d'habitude, cela dépend.
Tout d'abord, vous devez activer la journalisation GC pour avoir une vision claire de ce qui se passe. Vous pouvez l'activer avec -Xloggc:gc.log -XX:+PrintGCDetails
.
Si votre application passe beaucoup de temps dans un cycle GC, alors, oui, accordez le GC, sinon, cela ne vaut pas vraiment la peine.
Par exemple, si vous avez une jeune GC toutes les 100ms qui prend 10ms, vous passez 10% de votre temps dans la GC, et vous avez 10 collections par seconde (ce qui est huuuu énorme). Dans un tel cas, je ne passerais pas de temps à régler le GC, puisque ces 10 GC/s seraient toujours là.
3 - Une certaine expérience
J'ai eu un problème similaire sur une application qui créait une quantité énorme d'une classe donnée. Dans les journaux GC, j'ai remarqué que le taux de création de l'application était d'environ 3 Go/s, ce qui est beaucoup trop (allez... 3 gigaoctets de données par seconde ? !).
Le problème : Trop de GC fréquents causés par la création de trop d'objets.
Dans mon cas, j'ai attaché un profileur de mémoire et j'ai remarqué qu'une classe représentait un pourcentage énorme de tous mes objets. J'ai recherché les instanciations pour découvrir que cette classe était essentiellement une paire de booléens enveloppés dans un objet. Dans ce cas, deux solutions s'offraient à moi :
-
Retravailler l'algorithme de manière à ne pas renvoyer une paire de booléens mais à avoir deux méthodes qui renvoient chaque booléen séparément.
-
Mettre en cache les objets, sachant qu'il n'y avait que 4 instances différentes
J'ai choisi la seconde, car elle avait le moins d'impact sur l'application et était facile à introduire. Il m'a fallu quelques minutes pour mettre en place une usine avec un cache non sécurisé par les threads (je n'avais pas besoin de la sécurité des threads puisque je n'aurais finalement que 4 instances différentes).
Le taux d'allocation est passé à 1 Go/s, de même que la fréquence des jeunes GC (divisée par 3).
J'espère que cela vous aidera !