Du programme au processus
Comprendre ce qui se passe réellement lorsqu’un programme fonctionne.
Objectifs
À la fin de cette leçon, vous saurez :
- raconter le cheminement complet d'une commande, de la frappe clavier au matériel ;
- distinguer programme (fichier sur disque) et processus (instance vivante en RAM) ;
- expliquer compilation et interprétation avec des exemples concrets ;
- décrire les rôles respectifs du CPU, de la RAM et du stockage, et le travail de l'arbitre : le système d'exploitation.
🔗 Pour vous rafraîchir la mémoire : lecture de fichiers et aide (
cat,grep,man)
Le schéma global
Utilisateur
↓ tape une commande
Shell
↓ lance
Programme (processus)
↓ demande
Système d'exploitation (noyau)
↓ arbitre et exécute via
CPU / RAM / disque / réseau
C'est la chaîne complète que vous saurez raconter à la fin de ce cursus. Chaque couche s'appuie sur la précédente : l'utilisateur exprime une intention, le shell la traduit en lancement de programme, le programme fait le travail par délégation, et le matériel fournit la force brute. Cette leçon ouvre le capot de chaque étage.
Programme et processus : deux mots pour deux choses
La confusion est fréquente ; prenons un exemple réel et suivons-le.
Le fichier sur disque. ls est un fichier comme un autre, posé sur le stockage :
$ which ls
/usr/bin/ls
$ file /usr/bin/ls
/usr/bin/ls: ELF 64-bit LSB executable, x86-64 ...
Ce fichier contient des instructions machine : des nombres que le processeur sait interpréter directement (« additionne », « compare », « écris à l'adresse… »). Le format (ELF) est l'emballage standard des exécutables Linux. Ce fichier est passif : posé sur le disque, il ne fait rien du tout.
Le processus. Tapez ls dans deux terminaux en même temps : deux exécutions coexistent, chacune chargée à sa place en mémoire, avec son propre état (où en est-il ? quels fichiers a-t-il ouverts ?). Un processus est une instance vivante d'un programme :
programme = la recette imprimée (sur le disque)
processus = une cuisine en train de cuisiner cette recette (en RAM)
Deux cuisiniers peuvent suivre la même recette sans se gêner : deux processus peuvent venir du même programme. C'est pour cela qu'on peut lancer trois terminaux qui font tourner trois sleep simultanés — nous le ferons effectivement dans la prochaine leçon.
Et le code source ? C'est le texte que vous écrivez. Il subit lui aussi une transformation avant de devenir exécutable — c'est l'objet de la section suivante.
Compilation et interprétation
Le processeur ne comprend que ses instructions machine. Or vous écrirez du texte : JavaScript, TypeScript, SQL... Comment le fossé se franchit-il ? Deux grandes familles.
Compilation : un programme spécial (le compilateur) traduit tout le code source d'un coup, une fois pour toutes, en fichier exécutable. Ensuite on exécute ce fichier, et le source ne sert plus à rien à l'exécution.
code source ──(compilateur, une fois)──→ exécutable ──(lancement)──→ processus
main.c gcc a.out
Avantages : l'exécution est très rapide (rien à traduire pendant) et les erreurs de syntaxe sont attrapées avant tout lancement. Inconvénient : il faut recompiler à chaque modification. Exemples : C, Rust, Go.
Interprétation : un programme (l'interpréteur) lit le source et exécute chaque action au fur et à mesure, à chaque lancement.
code source ──(interpréteur, à chaque exécution)──→ actions exécutées
script.js node
Vous venez déjà d'en utiliser deux, sans y penser :
node mon-script.js # Node interprète du JavaScript
bash mon-script.sh # bash interprète du shell
Avantages : pas d'étape de build, on modifie et relance aussitôt. Inconvénients : l'interpréteur doit être installé partout où le code doit tourner, et certaines erreurs ne surgissent qu'à l'exécution, quand l'interpréteur atteint la ligne fautive.
Nuance honnête pour la suite : Node n'est pas un pur interpréteur. Son moteur (V8) compile aussi, mais à la volée et invisiblement, pour aller vite. Retenez le modèle simple (compilé d'avance / traduit en marchant) : il décrit correctement ce que vous observerez, et les détails viendront plus tard.
Que fait la machine ?
| Composant | Rôle | Analogie cuisine | Si on le coupe |
|---|---|---|---|
| CPU | exécute les instructions, une par une | le cuisinier | plus rien ne tourne |
| RAM | mémoire de travail : processus, variables, données en cours | le plan de travail | tout s'efface instantanément |
| Stockage | fichiers permanents : sources, programmes, documents | les placards et le livre de recettes | les fichiers redeviennent inaccessibles |
Trois relations à graver :
- La RAM est volatile, le stockage persistant. Éteindre la machine efface la RAM ; votre code source, lui, survit car il vit sur le disque. C'est pourquoi « sauvegarder » signifie toujours : faire passer des données de la RAM vers le stockage.
- Un processus vit en RAM. Au lancement, le système lit le programme sur le disque et le copie en mémoire ; ensuite le CPU y travaille. Les vitesses sont d'ailleurs dans cet ordre-là : le CPU est rapide, la RAM assez rapide, le disque lent — c'est pourquoi on charge tout en RAM plutôt que de relire le disque sans arrêt.
- Tout cela est fini. La RAM d'une VM se compte en gigaoctets, le disque en dizaines ou centaines. Quand la RAM est pleine, le système ralentit ou tue des processus ; quand le disque est plein, plus rien ne peut s'écrire. Vous verrez ces deux pannes en vrai dans votre carrière de développeur.
Le système d'exploitation, arbitre indispensable
Pourquoi ne pas laisser chaque programme parler directement au matériel ? Parce qu'un serveur fait tourner des dizaines de processus simultanément, tous avides du même CPU et de la même RAM. Sans arbitre, chaos. Le noyau Linux — le cœur du système d'exploitation — assure quatre missions permanentes :
- Charger : lire le programme depuis le disque, l'installer en RAM, préparer son état initial ;
- Ordonnancer : donner le CPU à chaque processus par tranches de quelques millisecondes, si vite qu'on croit à un parallélisme total ;
- Isoler : chaque processus reçoit sa propre zone de mémoire, protégée. Un bug dans un processus ne doit pas écraser la mémoire d'un voisin — ni celle du système ;
- Médier les accès : disque, réseau, terminal, horloge sont accessibles uniquement via lui, selon des règles strictes — dont vos droits d'utilisateur (souvenez-vous de
id: uid, groupes).
Conséquence essentielle pour tout le reste du cursus : un programme ne parle jamais directement au matériel. Il demande au système (on dit qu'il fait un « appel système ») : lis ce fichier, ouvre ce port réseau, écris ces octets. Le système vérifie, autorise ou refuse, puis agit. Toute l'administration serveur — permissions, ports, utilisateurs, limites de mémoire — découle de cette position d'arbitre.
Suivre une commande de bout en bout
Réassemblons tout avec node bonjour.js, ligne par ligne :
1. Vous tapez « node bonjour.js » + Entrée
2. Le shell découpe en deux mots, cherche « node » → trouve /usr/bin/node
3. Le shell demande au noyau : « lance ce programme avec ces arguments »
4. Le noyau crée un NOUVEAU processus : copie node en RAM, lui donne un identifiant (PID)
5. Dans ce processus, Node lit bonjour.js sur le disque et l'exécute instruction par instruction
6. L'instruction console.log("salut") devient : « écrire ce texte sur stdout »
7. Le stdout du processus est relié au terminal → le texte apparaît chez vous
8. Le script se termine → le processus rend son code de retour (sujet de la leçon 2-03)
9. Le noyau supprime le processus, libère sa RAM ; le shell affiche un nouveau prompt
Ne mémorisez pas : redessinez mentalement. Si vous savez refaire ce dessin, vous comprenez déjà plus que bien des développeurs expérimentés — et chaque chapitre suivant viendra détailler un étage de cette chaîne.
Exercice
- Créez
bonjour.jscontenantconsole.log("salut système");puis exécuteznode bonjour.js. Racontez (par écrit !) ce qui s'est passé en utilisant les mots : shell, processus, disque, RAM, stdout. - Lancez
sleep 100dans deux terminaux différents. Combien de processussleepexistent ? Combien de programmessleepexistent sur le disque ? - Quelle commande localise le fichier exécutable de
node? Quel dossier contient-il ? - Un ami vous dit : « j'ai sauvegardé mes variables dans la RAM, aucun risque de perte ». Où est l'erreur ?
Résumé
- Chaîne complète : utilisateur → shell → processus → noyau → matériel.
- Programme = fichier d'instructions sur disque (passif) ; processus = instance vivante en RAM (avec PID et état).
- Compilé : traduit avant (rapide, erreurs tôt). Interprété : traduit pendant (flexible, nécessite l'interpréteur).
- CPU exécute, RAM vit (volatile), disque conserve (persistant).
- Le noyau charge, ordonnance, isole et médie : aucun accès direct au matériel.
Correction disponibleCherchez d’abord par vous-même.Voir la correction
Correction
Réponses détaillées
Exercice 1. Récit attendu (formulations libres acceptées) : le shell a lu ma ligne et trouvé le programme node ; le noyau a créé un nouveau processus (copie de node en RAM, avec un PID) ; dans ce processus, Node a lu bonjour.js sur le disque et a exécuté la ligne ; console.log a écrit « salut système » sur stdout, canal relié au terminal, d'où l'affichage ; le processus s'est terminé et a rendu la main au shell.
Exercice 2. Deux processus sleep (deux instances vivantes, deux PID distincts — vérifiable avec ps aux | grep sleep) mais un seul programme /usr/bin/sleep sur le disque. C'est exactement la distinction recette/cuissons : le fichier est unique, les exécutions multiples.
Exercice 3.
$ which node
/usr/bin/node
which cherche dans les répertoires listés par PATH (leçon 2-04 pour approfondir) et répond par le chemin du fichier exécutable.
Exercice 4. La RAM est volatile : au redémarrage ou à la coupure de courant, tout ce qui y vivait disparaît. Une sauvegarde durable passe obligatoirement par le stockage (disque) — voire par une copie sur une autre machine, sujet traité bien plus loin dans le cursus.