Qu'est-ce que Rust a au lieu d'un garbage collector?

93

Je comprends que Rust n'a pas de ramasse-miettes et je me demande comment la mémoire est libérée lorsqu'une liaison est hors de portée.

Donc, dans cet exemple, je comprends que Rust récupère la mémoire allouée à «a» quand il est hors de portée.

{
    let a = 4
}

Le problème que j'ai avec cela, c'est d'abord comment cela se produit, et deuxièmement, n'est-ce pas une sorte de garbage collection? En quoi diffère-t-il du ramasse-miettes «typique»?

rix
la source
12
"La durée de vie des objets déterministes". Similaire à C ++.
user2864740
@ user2864740 Ce guide est bien dépassé. Le remplacement moderne serait probablement doc.rust-lang.org/book/references-and-borrowing.html .
Veedrac

Réponses:

73

Le nettoyage de la mémoire est généralement utilisé périodiquement ou à la demande, comme si le tas est presque plein ou au-dessus d'un certain seuil. Il recherche ensuite les variables inutilisées et libère leur mémoire, en fonction de l' algorithme .

Rust saurait quand la variable devient hors de portée ou que sa durée de vie se termine au moment de la compilation et insère ainsi les instructions LLVM / d'assemblage correspondantes pour libérer la mémoire.

Rust permet également une sorte de récupération de place, comme le comptage de références atomiques .

Ayonix
la source
En allouant de la mémoire lors de l'introduction de variables et en libérant de la mémoire lorsque la mémoire n'est plus nécessaire? Je ne sais pas vraiment ce que tu veux dire avec ça. Peut-être avons-nous alors des opinions différentes sur ce qu'est un GC.
Ayonix
1
Sa question est de savoir en quoi l'approche de Rust diffère d'un GC typique. J'ai donc expliqué ce qu'est un GC et comment Rust le fait sans GC.
Ayonix
1
doc.rust-lang.org/book/the-stack-and-the-heap.html l' explique assez bien. Oui, beaucoup de choses sont dans la pile mais encore moins un indicateur suffisant (voir encadré). J'ai laissé cela de côté par souci de simplicité, car la question se posait généralement
Ayonix
1
@Amomum En fait, Rust n'a pas de new()fonction ointe comme C, ce ne sont que des fonctions statiques, et en particulier quelque chose comme let x = MyStruct::new()crée son objet sur la pile. Le véritable indicateur de l'allocation de tas est Box::new()(ou l'une des structures qui dépendent de Box).
Mario Carneiro
1
Quels autres langages gèrent la gestion de la mémoire de la même manière que Rust?
still_dreaming_1
42

L'idée de base de la gestion des ressources (y compris la mémoire) dans un programme, quelle que soit la stratégie, est que les ressources liées à des «objets» inaccessibles peuvent être récupérées. Au-delà de la mémoire, ces ressources peuvent être des verrous mutex, des descripteurs de fichiers, des sockets, des connexions de base de données ...

Les langages dotés d'un ramasse-miettes analysent périodiquement la mémoire (d'une manière ou d'une autre) pour trouver des objets inutilisés, libèrent les ressources qui leur sont associées et enfin libèrent la mémoire utilisée par ces objets.

Rust n'a pas de GC, comment gère-t-il?

Rust est propriétaire. En utilisant un système de type affine , il suit quelle variable tient toujours un objet et, lorsqu'une telle variable sort de la portée, appelle son destructeur. Vous pouvez voir le système de type affine en vigueur assez facilement:

fn main() {
    let s: String = "Hello, World!".into();
    let t = s;
    println!("{}", s);
}

Rendements:

<anon>:4:24: 4:25 error: use of moved value: `s` [E0382]
<anon>:4         println!("{}", s);

<anon>:3:13: 3:14 note: `s` moved here because it has type `collections::string::String`, which is moved by default
<anon>:3         let t = s;
                     ^

ce qui illustre parfaitement qu'à tout moment, au niveau de la langue, la propriété est suivie.

Cette propriété fonctionne de manière récursive: si vous avez un Vec<String>(c'est-à-dire un tableau dynamique de chaînes), alors chacun Stringest détenu par le Vecqui lui-même appartient à une variable ou à un autre objet, etc ... ainsi, lorsqu'une variable sort de la portée, il libère récursivement toutes les ressources qu'il détenait, même indirectement. Dans le cas du, Vec<String>cela signifie:

  1. Libération de la mémoire tampon associée à chaque String
  2. Libération du tampon mémoire associé à Veclui - même

Ainsi, grâce au suivi de propriété, la durée de vie de TOUS les objets du programme est strictement liée à une (ou plusieurs) variables de fonction, qui finiront par sortir du champ d'application (lorsque le bloc auquel ils appartiennent se termine).

Remarque: c'est un peu optimiste, en utilisant le comptage de références ( Rcou Arc) il est possible de former des cycles de références et donc de provoquer des fuites de mémoire, auquel cas les ressources liées au cycle pourraient ne jamais être libérées.

Matthieu M.
la source
2
"Les langues avec un garbage collector analysent périodiquement la mémoire (d'une manière ou d'une autre)". Beaucoup le font mais ce n'est pas vrai en général. Les garbage collector en temps réel analysent de manière incrémentielle plutôt que périodique. Les langages de comptage de références comme Mathematica ne scannent pas du tout.
JD
@JonHarrop: Je ne compte pas le comptage de références comme un mécanisme complet de nettoyage de la mémoire car il doit être complété pour éviter les cycles de fuite. Quant à la différence incrémentale / périodique, c'est peut-être ma mauvaise maîtrise de l'anglais, mais je ne vois pas à quel point périodique ne couvre pas le cas incrémental ... Je pense que le bit "(d'une manière ou d'une autre)" transmet adéquatement que beaucoup de varié des approches existent. Dans tous les cas, si vous avez une meilleure façon de décrire succinctement Garbage Collection, veuillez suggérer. Je n'ai cependant pas l'intention de me lancer dans une explication à part entière: je n'en suis pas qualifié.
Matthieu M.
1
"Je ne compte pas le comptage de références comme un mécanisme complet de Garbage Collection puisqu'il doit être complété pour éviter les cycles de fuite". RC est classiquement considéré comme une forme de GC. Dans Mathematica et Erlang, par exemple, les cycles ne peuvent pas être créés par conception afin que RC ne fuit pas. Pour une perspective de haut niveau, voir «Une théorie unifiée de la collecte des ordures» cs.virginia.edu/~cs415/reading/bacon-garbage.pdf
JD
@JonHarrop: Vrai, si aucun cycle n'est possible, RC ne peut pas fuir.
Matthieu M.
2
"Je ne vois pas comment périodique ne couvre pas le cas incrémental". Les algorithmes d'arrêt du monde seraient considérés comme périodiques alors que le marquage tricolore est considéré comme incrémental, par exemple. Ils sont opposés dans ce contexte.
JD
6

Avec un langage dans lequel vous devez gérer manuellement la mémoire, la distinction entre la pile et le tas devient critique. Chaque fois que vous appelez une fonction, suffisamment d'espace est alloué sur la pile pour toutes les variables contenues dans la portée de cette fonction. Lorsque la fonction est renvoyée, le cadre de pile associé à cette fonction est "sauté" hors de la pile et la mémoire est libérée pour une utilisation future.

D'un point de vue pratique, ce nettoyage de mémoire par inadvertance est utilisé comme un moyen de stockage automatique de la mémoire qui sera effacé à la fin de la portée de la fonction.

Il y a plus d'informations disponibles ici: https://doc.rust-lang.org/book/the-stack-and-the-heap.html

Suisse
la source
3
Bien que l'utilisation de la pile soit pratique, les durées de vie des objets déterministes peuvent toujours être gérées si toutes les valeurs ont été «créées sur le tas». C'est donc un détail de mise en œuvre; pas nécessairement une stratégie linguistique.
user2864740
2
Tu continues à utiliser ce mot. Je ne pense pas que cela signifie ce que vous pensez que cela signifie.
Suisse
Signifie ce que je souhaite exprimer ; étant le contraire des durées de vie non déterministes. Faites une offre pour une meilleure phrase.
user2864740
Merci pour la réponse, j'ai donné les points au premier simplement parce qu'il a été soumis en premier. Les informations sont tout aussi utiles et valables.
rix le
@ user2864740 Les durées de vie déterministes des objets font référence à la capacité de dire exactement quand la mémoire de l'objet sera effacée une fois que son destructeur a été appelé. Cela n'a rien à voir avec la façon dont ce destructeur est appelé en premier lieu. Vous continuez à évoquer le même terme à plusieurs reprises même s'il n'a aucune signification directe pour la question.
Suisse