web-dev-qa-db-fra.com

Comment la JVM a-t-elle décidé de compiler JIT une méthode (catégoriser une méthode comme «chaude»)?

J'ai déjà travaillé avec -XX:+PrintCompilation, et je connais les techniques de base du compilateur JIT et pourquoi la compilation JIT est utilisée.

Pourtant, je n'ai toujours pas découvert comment la JVM décide de compiler JIT une méthode, c'est-à-dire "quand le bon moment est venu de compiler JIT une méthode".

Ai-je raison de supposer que chaque méthode commence à être interprétée et tant qu'elle n'est pas classée comme "méthode chaude", elle ne sera pas compilée? J'ai quelque chose dans le fond de ma tête que j'ai lu qu'une méthode est considérée comme "chaude" lorsqu'elle a été exécutée au moins 10 000 fois (après avoir interprété la méthode 10 000 fois, elle sera compilée), mais je dois admettre que je suis Je ne sais pas trop où je l'ai lu.

Donc, pour résumer ma question:

(1) La méthode every est-elle interprétée tant qu'elle n'a pas été classée comme méthode "chaude" (et donc compilée) ou existe-t-il des raisons pour que les méthodes soient compilées même si elles ne sont pas "chaudes" "?

(2) Comment la JVM classe-t-elle les méthodes en méthodes "non hot" et "hot"? Nombre d'exécution? Rien d'autre?

(3) S'il existe certains seuils (comme le nombre d'exécutions) pour les méthodes "à chaud", existe-t-il Java drapeaux (-XX:...) pour fixer ces seuils?

31
Markus Weninger

La politique de compilation HotSpot est assez complexe, en particulier pour la compilation par niveaux, qui est activée par défaut dans Java 8. Ce n'est ni un certain nombre d'exécutions, ni une question de paramètre CompileThreshold.

La meilleure explication (apparemment, la seule explication raisonnable) peut être trouvée dans les sources HotSpot, voir advancedThresholdPolicy.hpp .

Je vais résumer les principaux points de cette politique de compilation avancée:

  • L'exécution commence au niveau 0 (interprète).
  • Les principaux déclencheurs de la compilation sont
    1. compteur d'appel de méthode i;
    2. compteur de backedge b. Les branches en arrière indiquent généralement une boucle dans le code.
  • Chaque fois que les compteurs atteignent une certaine valeur de fréquence (TierXInvokeNotifyFreqLog, TierXBackedgeNotifyFreqLog), une politique de compilation est appelée pour décider quoi faire ensuite avec la méthode en cours d'exécution. En fonction des valeurs de i, b et de la charge actuelle des threads de compilateur C1 et C2, il peut être décidé de

    • poursuivre l'exécution dans l'interprète;
    • commencer le profilage dans l'interpréteur;
    • méthode de compilation avec C1 au niveau 3 avec les données de profil complet requises pour une recompilation ultérieure;
    • méthode de compilation avec C1 au niveau 2 sans profil mais avec possibilité de recompilation (peu probable);
    • enfin compiler la méthode avec C1 au niveau 1 sans profil ni compteur (également peu probable).

    Les paramètres clés ici sont TierXInvocationThreshold et TierXBackEdgeThreshold. Les seuils peuvent être ajustés dynamiquement pour une méthode donnée en fonction de la longueur de la file d'attente de compilation.

  • La file d'attente de compilation n'est pas FIFO, mais plutôt une file d'attente prioritaire.

  • Le code compilé en C1 avec les données de profil (niveau 3) se comporte de la même manière, sauf que les seuils pour passer au niveau suivant (C2, niveau 4) sont beaucoup plus élevés. Par exemple. une méthode interprétée peut être compilée au niveau 3 après environ 200 invocations, tandis que la méthode compilée C1 peut être recompilée au niveau 4 après plus de 5000 invocations.

  • Une politique spéciale est utilisée pour l'inlining de méthode. De minuscules méthodes peuvent être intégrées dans l'appelant même si elles ne sont pas "à chaud". Des méthodes un peu plus grandes ne peuvent être intégrées que si elles sont fréquemment appelées (InlineFrequencyRatio, InlineFrequencyCount).
55
apangin

Le paramètre principal pour contrôler cela est -XX:CompileThreshold=10000

Hotspot pour Java 8 utilise maintenant une compilation à plusieurs niveaux par défaut en utilisant un certain nombre d'étapes de compilation du niveau 1 à 4. Je crois que 1 n'est pas une optimisation. Le niveau 3 est C1 (basé sur le client client ) et le niveau 4 est C2 (basé sur le compilateur de serveur)

Cela signifie qu'une petite optimisation peut se produire plus tôt que prévu et qu'elle peut continuer à s'optimiser longtemps après avoir atteint le seuil de 10K. Le plus élevé que j'ai vu est l'analyse d'échappement, éliminant un StringBuilder après un million d'appels.

Remarque: une boucle itérative plusieurs fois peut déclencher le compilateur. par exemple. une boucle de 10K fois peut suffire.

1) Tant qu'une méthode n'est pas considérée comme suffisamment chaude, elle est interprétée. Cependant, certaines JVM (par exemple Azul Zing) peuvent compiler des méthodes au démarrage et vous pouvez forcer la JVM Hotspot à compiler une méthode via une API interne. Java 9 peut également avoir un compilateur AOT (Ahead Of Time) mais il est toujours en cours de recherche AFAIK

2) Nombre d'appels ou nombre d'itérations.

3) Oui -XX:CompileThreshold= étant le principal.

9
Peter Lawrey