November 26, 20255 min

Comment l'ownership prévient-il les memory leaks et data races ?

m
mayo

L'ownership est le système central de gestion mémoire de Rust, appliquant des règles strictes au moment de la compilation pour assurer la sécurité sans garbage collector. Il prévient les memory leaks et data races à travers une combinaison de règles d'ownership, move semantics, et borrowing.

s1 (moved) invalide : use after move s2 nouveau propriétaire du String "hello" buffer heap (inchangé) move take_ownership(s) → s droppé en fin de scope de la fonction un seul propriétaire à la fois : pas de double free, pas de fuite

Ownership en Rust

  • Chaque valeur a un propriétaire unique (variable).
  • Quand le propriétaire sort du scope, la valeur est droppée (trait Drop appelé).
  • L'ownership peut être transféré (moved), rendant la variable originale invalide.

Règles Clés

Move Semantics

Assigner une valeur heap-allocated (ex : String) à une autre variable transfère l'ownership, invalidant l'originale.

Exemple :

let s1 = String::from("hello");
let s2 = s1; // Ownership moved vers s2
// println!("{}", s1); // Erreur de compilation: value borrowed after move

Copy vs. Move

  • Les types avec taille connue (i32, bool) implémentent Copy et sont clonés automatiquement.
  • Les types heap-allocated (String, Vec) n'implémentent pas Copy et sont moved.

Appels de Function

Passer une valeur à une fonction la move ou la copie, suivant les mêmes règles.

Exemple :

fn take_ownership(s: String) { /* ... */ }

let s = String::from("hello");
take_ownership(s); // Ownership moved dans la fonction
// println!("{}", s); // Erreur: s est invalide

Comment l'Ownership Prévient les Memory Leaks

  • Cleanup Automatique : Quand le propriétaire sort du scope, Rust appelle drop pour libérer la mémoire (pas de free() manuel nécessaire).
  • Pas de Double Frees : Puisque seul un propriétaire existe, la valeur est droppée exactement une fois.

Comment l'Ownership Prévient les Data Races

  • Règles de Borrowing :
    • Emprunts immutables (&T) : Plusieurs autorisés, mais aucun emprunt mutable ne peut coexister.
    • Emprunts mutables (&mut T) : Un seul autorisé, et aucun autre emprunt ne peut exister.
  • Application au Compile-Time : Le compilateur rejette le code qui pourrait mener à des data races.

Exemple : Prévention de Data Race :

let mut data = vec![1, 2, 3];
let r1 = &data; // Borrowing immutable OK
let r2 = &data; // Autre borrow immutable OK
// let r3 = &mut data; // ERREUR: Cannot borrow as mutable while immutable borrows exist
println!("{:?}, {:?}", r1, r2);
Ce que le borrow checker autorise ensuite Emprunts déjà vivants vous demandez &data vous demandez &mut data aucun autorisé premier emprunt partagé autorisé accès exclusif r1 = &data, r2 = &data autant de partagés que voulu autorisé les partagés s'accumulent refusé cannot borrow as mutable m = &mut data exactement un refusé déjà emprunté mutablement refusé un seul &mut à la fois Dans l'exemple r1 et r2 sont encore vivants, donc `let r3 = &mut data;` tombe dans la case surlignée.

Points Clés

L'ownership assure :

  • Pas de dangling pointers (via lifetimes).
  • Pas de memory leaks (via Drop).
  • Pas de data races (via règles de borrowing).

Le modèle d'ownership de Rust garantit la memory safety et concurrency safety au moment de la compilation, délivrant performance et fiabilité.

Retour au blog
Partager ::