Pourquoi la JVM nécessite-t-elle un échauffement?

je comprends que dans la machine virtuelle Java (JVM), l'échauffement est potentiellement requis comme classes de chargement Java en utilisant un processus de chargement paresseux et comme tel vous voulez vous assurer que les objets sont initialisés avant de commencer les transactions principales. Je suis un développeur C++ et je n'ai pas eu à faire face à des exigences similaires.

Toutefois, les pièces que je ne suis pas en mesure de comprendre sont les suivantes:

  1. quelles parties du code devrait vous réchauffer?
  2. Même si Je réchauffe certaines parties du code, combien de temps reste-t-il chaud (en supposant que ce terme signifie seulement combien de temps vos objets de classe restent dans la mémoire)?
  3. Comment faut-il aider si j'ai des objets qui doivent être créés chaque fois que je reçois un événement?

prendre en considération pour un exemple une application qui devrait recevoir des messages sur une socket et les transactions pourraient être Nouvel Ordre, modifier L'ordre et annuler L'ordre ou la transaction confirmée.

Notez que l' l'application concerne le Trading haute fréquence (HFT) donc la performance est d'une importance extrême.

32
demandé sur Peter Lawrey 2016-03-24 13:43:04

7 réponses

quelles parties du code devrait vous réchauffer?

habituellement, vous n'avez rien à faire. Cependant, pour une application à faible latence, vous devriez réchauffer le chemin critique dans votre système. Vous devriez faire des tests unitaires, donc je vous suggère de les exécuter sur start up pour réchauffer le code.

même une fois votre code échauffé, vous devez vous assurer que vos caches CPU restent chaudes aussi. Vous pouvez voir un ralentissement significatif dans la performance après une opération de blocage par exemple, les e / s réseau, jusqu'à 50 micro-secondes. Ce n'est généralement pas un problème, mais si vous essayez de rester en dessous de 50 micro-secondes la plupart du temps, ce sera un problème, la plupart du temps.

Note: L'échauffement peut permettre à L'analyse des échappées de se déclencher et de placer des objets sur la pile. Cela signifie que ces objets n'ont pas besoin d'être optimisés ailleurs. Il est préférable de dresser le profil de votre application avant d'optimiser votre code.

Même si je réchauffe certaines parties de la code, combien de temps reste-t-il chaud (en supposant que ce terme signifie seulement combien de temps vos objets de classe restent en mémoire)?

Il n'y a pas de limite de temps. Cela dépend si le JIt détecte si l'hypothèse qu'il fait lors de l'optimisation du code s'est avéré être incorrect.

Comment faut-il aider si j'ai des objets qui doivent être créés chaque fois que je reçois un événement?

Si vous voulez une faible latence, ou à hautes performances, vous devez créer petits objets que possible. I aim to produce less than 300 KB / sec. Avec ce taux d'allocation, vous pouvez avoir un espace Eden assez grand pour recueillir mineure une fois par jour.

considérons par exemple une application qui est censée recevoir des messages sur une socket et les transactions pourraient être Nouvel Ordre, modifier L'ordre et annuler L'ordre ou la transaction confirmée.

je vous suggère de réutiliser les objets autant que possible, mais si c'est sous votre affectation budget, il ne vaut peut-être pas la peine de s'en inquiéter.

notez que l'application est sur Le Trading haute fréquence (HFT) donc la performance est d'une importance extrême.

vous pourriez être intéressé par notre logiciel open source qui est utilisé pour les systèmes HFT dans différentes banques D'investissement et fonds spéculatifs.

http://chronicle.logiciel/

mon application de production est utilisée pour le trading haute fréquence et chaque bit des temps de latence peut être un problème. Il est assez clair qu'au démarrage, si vous ne réchauffez pas votre application, cela conduira à une latence élevée de quelques millis.

En particulier, vous pourriez être intéressé par https://github.com/OpenHFT/Java-Thread-Affinity comme cette bibliothèque peut aider à réduire la planification de la gigue dans votre critique de threads.

et aussi il est dit que les sections critiques du code qui nécessitent un warmup devraient être lancées (avec des messages faux) atleast 12K fois pour qu'il fonctionne de manière optimisée. Pourquoi et comment ça fonctionne?

le Code est compilé en utilisant le(S) thread (s) d'arrière-plan. Cela signifie que même si une méthode peut être éligible pour compiler en code natif, cela ne signifie pas qu'elle l'a fait esp au démarrage lorsque le compilateur est déjà assez occupé. 12K n'est pas déraisonnable, mais il pourrait être plus élevée.

22
répondu Peter Lawrey 2016-03-24 22:02:50

le réchauffement renvoie au fait d'avoir un morceau de code exécuté suffisamment de fois pour que le JVM cesse d'interpréter et compile vers natif (au moins pour la première fois). En général, c'est quelque chose que tu ne veux pas faire. La raison en est que la JVM recueille des statistiques sur le code en question qu'elle utilise lors de la génération du code (ce qui s'apparente à des optimisations guidées par profil). Donc, si un morceau de code en question est "réchauffé" avec de fausses données qui a des propriétés différentes que les données réelles, vous pourriez bien être mal performance.

EDIT: puisque la JVM ne peut pas effectuer d'analyse statique de programme entier (elle ne peut pas savoir quel code va être chargé par l'application), elle peut à la place faire quelques conjectures sur les types à partir des statistiques qu'elle a recueillies. Par exemple, lorsqu'on appelle une fonction virtuelle (en langage C++) à un emplacement d'appel exact et qu'elle détermine que tous les types ont la même implémentation, alors l'appel est promu à l'appel direct (ou même inlined). Si, plus tard, cette hypothèse est prouvée être faux, alors l'ancien code doit être "non compilé" pour se comporter correctement. AFAIK HotSpot classifie les sites d'appel comme monomorphiques (implémentation unique), bi-morphiques (exactement deux..transformé en si (imp1-type) {imp1} else {imp2} ) et polymorphe..virtuel de l'expédition.

et il y a un autre cas de recompilation..lorsque vous avez hiérarchisé-compilation. Le premier niveau passera moins de temps à essayer de produire du bon code et si la méthode est "assez chaud" alors le plus cher le générateur de code de compilation démarre.

18
répondu MB Reynolds 2016-03-24 13:08:23

Warm-up est rarement . Il est important de s'assurer que le temps d'échauffement JIT n'altère pas les résultats lors de tests de performance par exemple.

dans le code de production normal vous voyez rarement le code qui est destiné à l'échauffement. Le JIT va s'échauffer pendant le traitement normal, donc il y a très peu d'avantage à introduire du code supplémentaire juste pour cela. Dans le pire des cas, vous pourriez introduire des bogues, passer du temps de développement supplémentaire et même nuire performance.

a moins que vous ne sachiez avec certitude que vous avez besoin d'une sorte d'échauffement, ne vous en faites pas. L'exemple d'application que vous avez décrit n'a certainement pas besoin.

9
répondu Kayaman 2016-03-24 10:57:38

quelles parties du code devrait vous chauffe?

Il n'y a pas de réponse à cette question en général. Il dépend entièrement de votre application.

Même si je chauffe certaines parties du code, combien de temps reste-t-il chaud (en supposant que ce terme signifie seulement combien de temps vos objets de classe restent en mémoire)?

Les objets restent en mémoire aussi longtemps que votre programme a une référence à eux, en l'absence de toute référence faible utilisez ou quelque chose de similaire. Apprendre quand votre programme "a une référence" à quelque chose peut être un peu plus obscur que vous pourriez penser à première vue, mais il est la base pour la gestion de la mémoire en Java et vaut la peine de l'effort.

Comment est-ce que cela aide si j'ai des objets qui doivent être créés à chaque fois J'ai un message d'événement.

cela dépend entièrement de l'application. Il n'y a pas de réponse en général.

je vous encourage à étudier et à travaillez avec Java pour comprendre des choses comme le téléchargement de classe, la gestion de la mémoire et la surveillance des performances. Il faut un certain temps pour instancier un objet, en général il faut plus de temps pour charger une classe (ce qui, bien sûr, est généralement fait beaucoup moins souvent). , une fois qu'une classe est chargé, il reste en mémoire pour la durée de vie du programme, c'est le genre de chose que vous devez comprendre, et pas seulement d'obtenir une réponse.

Il y a aussi des techniques pour apprendre si tu ne les connais pas déjà. Certains programmes utilisent des "pools" d'objets, instanciés avant qu'ils ne soient réellement nécessaires, puis transmis pour faire le traitement une fois que le besoin se présente. Cela permet une partie critique du programme pour éviter le temps passé instanciating au cours de la période critique. Les piscines conservent une collection d'objets (10? 100? 1000? 10000?), et d'instancier plus si besoin, etc. Mais Gérer les piscines est un effort de programmation important, et, bien sûr, vous occupez mémoire avec les objets dans les piscines.

il serait tout à fait possible d'utiliser assez de mémoire pour déclencher la collecte des ordures beaucoup plus souvent, et ralentir le système que vous aviez L'intention d'accélérer. C'est pourquoi vous devez comprendre comment cela fonctionne, pas seulement "obtenir une réponse".

autre considération -- de loin la plus grande partie des efforts déployés pour rendre les programmes plus rapides sont gaspillés, comme dans inutile. Sans grande expérience de l'application considérée, et/ou mesure du système, vous ne savez tout simplement pas où (ou si) optimisation sera perceptible. Conception du système / programme pour éviter les cas pathologiques de lenteur sont utiles, et ne prennent pas presque le temps et l'effort de l '"optimisation". La plupart du temps c'est toutes les toutes les nous devons.

-- edit -- ajouter juste-à-temps de la compilation de la liste de choses à étudier et à comprendre.

2
répondu arcy 2016-03-24 11:06:41

pourquoi la JVM a-t-elle besoin d'échauffement?

Modernes (J)VMs recueillir des statistiques lors de l'exécution sur le code qui est le plus souvent utilisé et comment il est utilisé. Un exemple (parmi des centaines sinon des milliers) est l'optimisation des appels vers des fonctions virtuelles (en C++) qui n'ont que sur l'implémentation. Ces statistiques ne peuvent, par définition, être collectées qu'à un moment donné.

le chargement de classe lui-même fait partie de l'échauffement aussi bien, mais il se produit évidemment automatiquement avant le exécution de code dans ces classes, il n'y a donc pas grand chose à craindre

quelles parties du code devrait vous chauffe?

la partie qui est cruciale pour la performance de votre application. L'important est de "réchauffer" exactement de la même manière qu'il est utilisé lors de l'utilisation normale, sinon la mauvaise optimisations sera fait (et défait).

Même si je chauffe certaines parties du code, combien de temps reste-t-il chaud (en supposant que ce terme signifie seulement combien de temps vos objets de classe restent dans la mémoire)?

c'est vraiment difficile à dire fondamentalement le compilateur JIT surveille constamment l'exécution et les performances. Si un seuil est atteint, il essaiera d'optimiser les choses. Il continuera ensuite à surveiller les performances pour vérifier que l'optimisation aide réellement. Si ce n'est pas le cas, le code risque de ne pas être optimisé. Aussi des choses peuvent arriver, qui invalident les optimisations, comme le chargement de nouvelles classes. Je voudrais examiner ces choses ne sont pas prévisibles, du moins pas basées sur une réponse stackoverflow, mais il y a des outils pour vous dire ce que fait le JIT: https://github.com/AdoptOpenJDK/jitwatch

Comment faut-il aider si j'ai des objets qui doivent être créés chaque fois que je reçois un événement.

un exemple simple pourrait être: vous créez des objets à l'intérieur d'une méthode, puisqu'une référence sort de la portée de la méthode, ces objets seront stockés sur le tas, et éventuellement ramassée par le ramasseur d'ordures. Si le code qui utilise ces objets est fortement utilisé, il pourrait finir par obtenir inlined dans une seule grande méthode, peut-être réorganisé au-delà de la reconnaissance, jusqu'à ce que ces objets vivent seulement à l'intérieur de cette méthode. À ce moment-là, ils peuvent être placés sur la pile et être retirés lorsque la méthode sort. Cela peut permettre d'économiser d'énormes quantités de collecte des ordures et ne se produira qu'après un certain échauffement.

Avec tout ce que dit: je suis sceptique sur l'idée que l'on doit faire rien de spécial pour l'échauffement. Il suffit de démarrer votre application,et de l'utiliser et le compilateur JIT fera très bien. Si vous rencontrez des problèmes, alors apprenez ce que le JIT fait avec votre application et comment affiner ce comportement ou comment écrire votre application afin qu'il bénéficie le plus.

le seul cas où je suis au courant du besoin d'échauffement est celui des points de repère. Parce que si vous le négligez là-bas, vous obtiendrez de faux résultats presque garantis.

2
répondu Jens Schauder 2016-03-24 11:09:25

C'est tout JIT compilateur, qui est utilisé sur l' JVM pour optimiser le bytecode dans l'exécution (parce que javac ne peut pas utiliser des techniques d'optimisation avancées ou agressives en raison de la nature indépendante de la plate-forme du bytecode)

  1. vous pouvez réchauffer le code qui traitera vos messages. En fait, dans la plupart des cas, vous n'avez pas besoin de faire à elle par des cycles Spéciaux d'échauffement: il suffit de laisser l'application pour commencer et traiter certains des premiers messages -JVM va essayer de faire son meilleur pour analyser l'exécution de code et faire des optimisations :) manuel warm-up avec de faux échantillons peut donner des résultats encore pires

  2. le code sera optimisé après un certain temps et sera optimisé jusqu'à ce qu'un événement dans l'état du programme-flow puisse dégrader le code (après lui JIT compilateur va essayer d'optimiser le code à nouveau - ce processus ne finit jamais)

  3. les objets à courte durée de vie sont eux aussi des sujets à optimiser, mais en général cela devrait aider votre message traite le code titulaire pour être plus efficace

2
répondu Cootri 2016-03-24 11:21:18

je l'ai toujours imaginé comme suit:

vous (un développeur C++) pouvez imaginer un automatisé approche itérative par l' jvm compilation/chargement à chaud/remplacement de divers bits et pièces par (l'analogue imaginaire de)gcc -O0,-O1,-O2,-O3 variantes (et parfois de revenir si elle le juge nécessaire)

je suis sûr que ce n'est pas strictement ce qui se produit mais cela pourrait être une analogie utile pour un dev C++.

Sur un jvm standard le temps qu'il faut pour qu'un échantillon soit pris en considération pour jit est fixé par -XX:CompileThreshold qui est 1500 par défaut. (Sources et versions de jvm varient - mais je pense que c'est pour JVM 8)

plus loin a livre que j'AI sous la main déclare sous le chapitre JIT de L'hôte Performace (p59) que les optimisations suivantes sont faites pendant JIT:

  • Inline
  • Verrouillage de l'élimination
  • Virtual appel d'élimination
  • Non volatiles de mémoire d'écrire élimination
  • Natif de génération de code

EDIT:

concernant les commentaires

je pense que 1500 peut être juste assez pour suggérer JIT qu'il doit compiler le code en natif et arrêter d'interpréter. seriez-vous d'accord?

Je ne sais pas si c'est juste un indice, mais puisque openjdk est open-source permet de regarder les différentes limites et les nombres dans globals.hpp#l3559@ver-a801bc33b08c (pour jdk8u)

(je ne suis pas une jvm dev cela peut être complètement mauvais endroit à regarder)

compiler un code en natif ne signifie pas nécessairement qu'il est aussi optimisé.

à ma compréhension - vrai; surtout si vous voulez dire -Xcomp (force compiler) - this blog même les états qu'il empêche la jvm de faire de profilage - optimisant donc - si vous n'exécutez pas -Xmixed (valeur par défaut).

ainsi un timer se déclenche pour échantillonner le code natif fréquemment utilisé et optimiser le même. Savez-vous comment on peut contrôler cet intervalle de temps?

je ne sais vraiment pas les détails, mais l' gobals.hpp I linked en effet définit certains intervalles de fréquences.

1
répondu birdspider 2016-03-25 14:31:30