Reference Counting
Lecture 5 min. âą
Bonjour Ă toutes et Ă tous đ
Dans lâarticle sur le boxing, on a vu que le clonage Ă©tait trĂšs loin dâĂȘtre gratuit.
Aujourdâhui nous allons voir une maniĂšre de cloner presque gratuitement. đ
Utilisons le mĂȘme exemple.
Déclarons une structure Person
struct Person {
name: String,
age: u8
}Elle contient deux champs:
- name : une String donc une référence et une slice quelque part en Heap
- age : un entier naturel
Déclarons une instance de Person et affectons-la à la variable p.

Nous nous retrouvons donc à avoir un espace mémoire dans la Stack qui est référencé par p.
Mais ce nâest pas tout car p.name rĂ©fĂ©rence aussi sa slice qui vie dans la Heap. (ici initialisĂ© Ă âtotoâ)
Nous possédons également p.age qui réside dans la Stack.

Nous allons utiliser un autre outil de la bibliothĂšque standard qui se nomme Rc pour Reference Counting.
Tout comme pour Box, la syntaxe est simple.
let rc = Rc::new(12);12 est dĂ©sormais dans la Heap, mais il va y avoir quelques diffĂ©rences avec le Box::new. đ
Appliquons le Ă p.

Et voyons ce que ça produit en mémoire.
Tout dâabord on dĂ©place p dans le contexte de Rc::new.

On vient wrapper nos données dans un conteneur qui possÚde deux champs:
- data : nos données
- count: un entier
Le compteur est initialisé à 1.
En réalité le conteneur est une
RcBoxet le champcountexiste en deux version weak et strong. Mais pour les besoins de vulgarisations je ne rentrerai pas dans les détails.
On vient alors allouer avec un Box::new de la place dans la Heap

On déplace alors vers la Heap notre RcBox.

On récupÚre alors une référence vers la RcBox

Que lâon peut ensuite renvoyĂ© dans le contexte main.

On sort de la méthode Rc::new ce qui a pour action de détruire la frame.
On se retrouve alors avec rc_p une référence vers une RcBox dans la Heap.

Bon pour le moment, ça semble juste un Box::new avec des Ă©tapes supplĂ©mentaires, mais promis tout ça a un sens. đ
Pour cela, clonons rc_p.

MĂȘme combat que pour Box::clone, on créé une rĂ©fĂ©rence que lâon copie dans Rc::clone.

Mais cette fois-ci pas de vrai clone.
On incrémente seulement le compteur de la RcBox.
Il passe de 1 Ă 2.
On créé une nouvelle rĂ©fĂ©rence qui pointe vers la mĂȘme RcBox.

Et on retourne la référence dans le contexte main.

Nous avons maintenant dans main, deux rĂ©fĂ©rences qui pointe vers la mĂȘme RcBox.
Le compteur de la RcBox est de 2.

Maintenant on décide de déplacer la Rc<Person>, rc_p_clone dans la méthode f1.
Voyons ce qui se passe.

La référence est déplacée dans le contexte de f1.

f1 termine.

Le drop est déclenché.
Il a pour effet de décrémenter de 1 le compteur de la RcBox.
Mais comme le compteur est supérieur à 0, il ne se passe rien.

f1 est terminé, mais la RcBox est toujours dans la Heap

Appelons f1 avec rc_p cette fois-ci, la derniÚre référence existante de la RcBox.

MĂȘme combat, on dĂ©place dans f1.

f1 se termine

Le drop est déclenché, on décrémente le compteur.

Mais cette fois-ci, le compteur vaut maintenant 0.
On libÚre la mémoire occupée par la RcBox et par la String également.

f1 est terminée.

On détruit la frame

main se termine

On détruit la frame, fin du programme.

Alors à quoi tout ça sert?
En synchrone, Ă presque rien, en tout cas je nâai jamais eu dâexemple vraiment parlant qui nâaurait pas pu se rĂ©gler par une rĂ©fĂ©rence non-mutable et une lifetime adĂ©quate.
Par contre son grand-frĂšre Arc est la pierre angulaire de lâasynchronisme facile en Rust.
Il y a aussi le patterm de lâInterior Mutability qui utilise les Rc.
On verra ces deux aspects dans des prochains articles.
Tout ce que vous devez retenir câest que cela permet Ă Rust de compter le nombre de rĂ©fĂ©rence active et de libĂ©rer la mĂ©moire au moment propice.
Câest le mĂȘme fonctionnement quâun garbage collector, mais sans devoir arrĂȘter le temps et lâespace pour compter vu que les objets se comptent eux-mĂȘme.
