Mémoire et ramasse-miettes dans Rust : comment un langage sans GC gère les ressources

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Pourquoi Rust n'a-t-il pas besoin de ramasse-miettes tout en étant sûr ?

\n\n

Lorsque les développeurs habitués à Python, Java ou C# entendent parler de Rust pour la première fois, l'absence de ramasse-miettes (GC) traditionnel les effraie souvent. « Comment ça ? pensent-ils. Sans GC, on retourne à l'époque de la gestion manuelle de la mémoire, des fuites et des segmentation fault ? »

\n\n

Révélation : non, on n'y retourne pas. Rust propose une troisième voie — le système de propriété (ownership), qui garantit la sécurité mémoire dès la compilation. Pas d'exécution, pas de GC, pas de pointeurs sauvages. Seulement des règles claires et un compilateur qui vous empêche de vous tirer une balle dans le pied.

\n\n

Dans cet article, nous verrons comment la mémoire est organisée dans Rust, ce que sont RAII, la propriété, l'emprunt et les durées de vie, et pourquoi tout cela fait de Rust l'un des langages de programmation système les plus fiables.

\n\n

Comment la mémoire est organisée dans Rust : pile et tas

\n\n

Comme dans tout langage bas niveau, la mémoire dans Rust est divisée en deux régions principales :

\n\n
    \n
  • La pile (stack) — mémoire rapide, de taille limitée, fonctionnant selon le principe LIFO. Elle stocke les variables locales, les arguments de fonction et les adresses de retour.
  • \n
  • Le tas (heap) — mémoire plus lente mais flexible, utilisée pour les données dont la taille est inconnue à la compilation (par exemple, String, Vec, Box).
  • \n
\n\n

En C++, vous décidez vous-même quand allouer et libérer le tas (via new/delete). En Java ou Python, c'est le ramasse-miettes qui le fait pour vous, en arrêtant périodiquement le programme. Rust, quant à lui, utilise le système de propriété, qui libère automatiquement la mémoire dès qu'une variable sort de sa portée.

\n\n

Exemple : allocation mémoire de base

\n\n
fn main() {\n    let s = String::from("Bonjour le monde !"); // allocation mémoire dans le tas\n    println!("{}", s);\n} // ici s sort de la portée, la mémoire est libérée
\n\n

Remarquez : pas de free() ni de delete. À la fin du bloc, le compilateur insère implicitement un appel au destructeur — drop(). C'est ce qu'on appelle RAII (Resource Acquisition Is Initialization) — la ressource est acquise lors de l'initialisation et libérée lors de la destruction de l'objet.

\n\n

Propriété (Ownership) : la règle principale de Rust

\n\n

Le système de propriété dans Rust repose sur trois règles simples :

\n\n
    \n
  1. Chaque valeur dans Rust a exactement un propriétaire (owner).
  2. \n
  3. Lorsque le propriétaire sort de la portée, la valeur est supprimée.
  4. \n
  5. Le propriétaire peut être transféré (move) ou temporairement prêté (borrow).
  6. \n
\n\n

Ça a l'air ennuyeux ? Voyons comment cela fonctionne en pratique.

\n\n

Transfert (Move)

\n\n
fn main() {\n    let s1 = String::from("hello");\n    let s2 = s1; // s1 est transféré dans s2\n    // println!("{}", s1); // Erreur ! s1 ne possède plus les données\n    println!("{}", s2); // OK\n}
\n\n

En C++, une telle affectation entraînerait deux pointeurs vers la même mémoire — et une double libération. En Rust, le compilateur interdit simplement d'utiliser s1 après le transfert. Pas de fuites, pas de doubles suppressions.

\n\n

Copie (Copy)

\n\n

Les types simples, comme les entiers, les booléens et les caractères, implémentent le trait Copy. Pour eux, l'affectation crée une copie complète :

\n\n
fn main() {\n    let x = 42;\n    let y = x;\n    println!("x = {}, y = {}", x, y); // Les deux sont accessibles !\n}
\n\n

Pourquoi ? Parce que i32 est stocké sur la pile, et le copier revient simplement à copier quelques octets. Peu coûteux et sûr.

\n\n

Emprunt (Borrowing) et références

\n\n

Que faire si vous devez donner temporairement accès aux données sans transférer la propriété ? Utiliser des références. Rust permet d'emprunter une valeur par référence.

\n\n
fn main() {\n    let s = String::from(                

Blogs

Book Recommendations