Compilateur vs interpréteur vs JIT : les différences expliquées

Il existe trois manières principales d'exécuter du code source. Un compilateur (ahead-of-time, ou AOT) traduit tout le programme en code machine avant son exécution. Un interpréteur lit et exécute le programme au fur et à mesure, sans produire de fichier de code machine séparé. Un compilateur just-in-time (JIT) commence par interpréter, puis compile en code machine les parties fréquemment utilisées pendant l'exécution du programme. De nombreux langages combinent ces approches.

CritèreCompilateur (AOT)InterpréteurCompilateur JIT
Moment de la traduction du codeAvant l'exécution : tout le programme devient du code machinePendant l'exécution : le programme est lu et exécuté pas à pasPendant l'exécution : le code fréquemment utilisé est compilé en code machine
DémarrageRapide (mais nécessite d'abord une étape de build)Rapide, sans étape de buildPlus lent au début, jusqu'à ce que le code soit « chaud »
Vitesse d'exécutionLa plus rapide et la plus prévisibleLa plus lente, souvent plusieurs fois plus lente que le code compiléProche de celle du code compilé après le warm-up, parfois plus rapide grâce aux informations d'exécution
PortabilitéUn binaire par plateformePortable : fonctionne partout où l'interpréteur existeBytecode portable, avec un runtime spécifique à la plateforme
Détection des erreursDe nombreuses erreurs sont détectées à la compilationLes erreurs apparaissent lorsque la ligne fautive s'exécuteDépend du langage
Utilisation mémoireFaible surcoût à l'exécutionL'interpréteur lui-même reste en mémoireMémoire supplémentaire pour le compilateur et le cache de code compilé
Cycle de développementModifier, compiler, exécuterModifier et exécuter immédiatementGénéralement modifier et exécuter, ou compiler en bytecode
Exemples de langagesC, C++, Rust, GoPython classique (CPython), Ruby, scripts shellJava (HotSpot), JavaScript (V8), C# (.NET), PyPy

Les valeurs indiquées sont des ordres de grandeur typiques et varient selon la génération de procédé et le produit.

Quand choisir l'un ou l'autre ?

Compilateur
Lorsque les performances, la petite taille et un comportement prévisible comptent : systèmes d'exploitation, jeux, firmware embarqué.
Interpréteur
Pour les expérimentations rapides, les scripts et l'apprentissage, où la rapidité de développement compte plus que la vitesse d'exécution.
JIT
Pour les programmes de longue durée sur une plateforme portable qui ont besoin de vitesse, comme les navigateurs web et les applications serveur.

Questions fréquentes

Python est-il compilé ou interprété ?

L'implémentation standard, CPython, compile le code source en bytecode puis l'interprète. D'autres implémentations comme PyPy ajoutent un compilateur JIT pour plus de vitesse.

Java est-il compilé ou interprété ?

Les deux. Java est compilé à l'avance en bytecode, que la JVM interprète puis compile en JIT en code machine pendant l'exécution du programme.

Pourquoi le code compilé est-il plus rapide ?

Tout le programme est traduit en code machine optimisé avant son exécution : rien n'a besoin d'être interprété à l'exécution.

Qu'est-ce que le warm-up d'un compilateur JIT ?

Au début, le programme s'exécute dans un interpréteur, et le JIT compile le code « chaud » une fois qu'il l'a vu s'exécuter souvent. Jusque-là, la vitesse est plus faible.

Vérifier vos connaissances

Quelle différence entre compilateur et interpréteur est correcte ?

  1. ALe compilateur traduit avant l'exécution, l'interpréteur exécute en lisant
  2. BLe compilateur traduit ligne par ligne pendant l'exécution, l'interpréteur traduit tout avant l'exécution
  3. CLe compilateur ne traite que le calcul numérique, l'interpréteur que le traitement de texte
Afficher la réponse et l'explication

Réponse : A. Le compilateur traduit avant l'exécution, l'interpréteur exécute en lisant

Le compilateur traduit l'ensemble du programme en code machine ou équivalent avant l'exécution, puis exécute le résultat de la traduction. La traduction prend du temps, mais l'exécution est plus rapide et l'on peut consacrer du temps à l'optimisation. L'interpréteur interprète et exécute le programme en le lisant ; on peut essayer immédiatement, mais l'exécution tend à être plus lente. En pratique, de nombreuses approches combinent les deux, par exemple traduction en bytecode puis interprétation, avec compilation JIT des parties fréquemment utilisées. La distinction ne porte pas sur le type de traitement.

Quelle caractéristique d'un environnement d'exécution utilisant la compilation JIT est correcte ?

  1. ATout le programme est traduit en code machine avant l'exécution puis distribué
  2. BLes parties souvent utilisées sont converties en code machine pendant l'exécution, avec accès aux informations d'exécution
  3. CAucun code machine n'est utilisé, et le bytecode est interprété instruction par instruction indéfiniment
Afficher la réponse et l'explication

Réponse : B. Les parties souvent utilisées sont converties en code machine pendant l'exécution, avec accès aux informations d'exécution

Avec la compilation JIT, le bytecode est d'abord exécuté par interprétation ; lorsqu'une partie souvent exécutée (point chaud) est repérée, elle est compilée en code machine pendant l'exécution. Les informations d'exécution, comme les branches réellement empruntées ou les types effectivement passés, permettent des optimisations audacieuses difficiles en compilation préalable. Un mécanisme de retour à l'interprétation est prévu si les hypothèses s'avèrent fausses. La traduction préalable complète est la compilation anticipée (AOT), l'interprétation seule l'interpréteur pur.

Quel est le principal avantage d'utiliser, à l'intérieur d'un compilateur, une représentation intermédiaire (IR) indépendante du langage source comme du CPU ?

  1. AElle permet de compiler sans lire le code source
  2. BLe CPU pouvant l'exécuter telle quelle, la génération de code machine devient inutile
  3. CElle sépare la partie avant propre à chaque langage de la partie arrière propre à chaque CPU, et les optimisations peuvent être partagées
Afficher la réponse et l'explication

Réponse : C. Elle sépare la partie avant propre à chaque langage de la partie arrière propre à chaque CPU, et les optimisations peuvent être partagées

Pour prendre en charge M langages et N CPU, un compilateur par combinaison en exigerait M×N ; avec une représentation intermédiaire commune, M parties avant (frontend) du langage vers l'IR et N parties arrière (backend) de l'IR vers le CPU suffisent. La plupart des optimisations, réalisées une fois sur l'IR, profitent à tous les langages et CPU. L'IR n'est pas directement exécutable par le CPU et doit finalement être convertie en code machine.

  1. Quel est le rôle de l'analyse lexicale d'un compilateur ?
  2. Que fait l'analyse syntaxique d'un compilateur ?

Questions d'entraînement sur Compilateurs

Termes clés expliqués

Compilation JIT
Méthode qui compile en langage machine, pendant l'exécution, les parties les plus souvent exécutées d'un programme. Elle permet des optimisations exploitant les informations d'exécution. Utilisée notamment dans les environnements Java et JavaScript.

Comparatifs associés