Inconvénients de la gestion de la mémoire basée sur la portée

38

J'aime beaucoup la gestion de la mémoire en fonction de la portée (SBMM), ou RAII , comme il est plus communément appelé (source de confusion) par la communauté C ++. Autant que je sache, à l'exception de C ++ (et C), il n'y a pas d'autre langage courant utilisé aujourd'hui qui fait de SBMM / RAII leur principal mécanisme de gestion de la mémoire. Ils préfèrent plutôt utiliser le garbage collection (GC).

Je trouve cela assez déroutant, car

  1. SBMM rend les programmes plus déterministes (vous pouvez dire exactement quand un objet est détruit);
  2. dans les langues qui utilisent GC, vous devez souvent gérer manuellement les ressources (voir la section Fermeture de fichiers en Java, par exemple), ce qui va en partie à l’encontre de l’objet de GC et est également sujet à des erreurs;
  3. La mémoire de tas peut aussi (très élégamment, imo) être liée à la portée (voir std::shared_ptren C ++).

Pourquoi SBMM n'est-il pas plus utilisé? Quels sont ses inconvénients?

Paul
la source
1
Quelques inconvénients (notamment concernant la vitesse) sont discutés dans Wikipedia: fr.wikipedia.org/wiki/…
Philipp
2
Le problème de gestion manuelle des ressources de Java est un effet secondaire de ne pas garantir que la finalize()méthode d' un objet sera appelée avant la récupération de place. En réalité, cela crée la même classe de problèmes que la récupération de place est supposée résoudre.
Blrfl
7
@ Blrfl Nonsense. Une gestion "manuelle" des ressources (pour les ressources autres que la mémoire, évidemment) serait préférable même si ce "problème" n'existait pas, car le CPG peut s'exécuter très longtemps après que la ressource soit inutilisée, voire pas du tout. Ce n'est pas un problème pour la mémoire , et la gestion de la mémoire est tout ce que la récupération de place est censée résoudre.
4
btw. J'aime me référer à SBRM car vous pouvez utiliser le même mécanisme pour gérer les ressources en général, pas seulement la mémoire.
PlasmaHH

Réponses:

27

Commençons par postuler que la mémoire est de loin (des dizaines, des centaines voire des milliers de fois) plus commune que toutes les autres ressources combinées. Chaque variable, objet, membre d'objet a besoin de mémoire allouée et libérée ultérieurement. Pour chaque fichier que vous ouvrez, vous créez des dizaines à des millions d'objets pour stocker les données extraites du fichier. Chaque flux TCP est associé à un nombre illimité de chaînes d'octets temporaires créées pour être écrites dans le flux. Sommes-nous sur la même page ici? Génial.

Pour que RAII fonctionne (même si vous avez des pointeurs intelligents prêts à l'emploi pour chaque cas d'utilisation sous le soleil), vous devez en assurer la propriété . Vous devez analyser qui doit posséder tel ou tel objet, qui ne doit pas, et lorsque la propriété doit être transférée de A à B. Bien sûr, vous pouvez utiliser la propriété partagée pour tout , mais vous émuleriez un GC par des pointeurs intelligents. À ce stade, il devient beaucoup plus facile et rapide d’intégrer le CPG dans le langage.

Le ramassage des ordures vous libère de cette préoccupation pour la ressource de loin la plus utilisée, la mémoire. Bien sûr, vous devez toujours prendre la même décision pour les autres ressources, mais celles-ci sont beaucoup moins courantes (voir ci-dessus) et la propriété complexe (par exemple, partagée) l'est également. La charge mentale est réduite de manière significative.

Maintenant, vous nommez quelques inconvénients à rendre toutes les valeurs ramassées. Cependant, il est extrêmement difficile d’ intégrer à la fois des types de CPG et de valeur sécurisés avec RAII dans une seule langue. Il est donc peut-être préférable de migrer ces compromis par d’autres moyens.

La perte de déterminisme n’est pas si grave dans la pratique, car elle n’affecte que la durée de vie des objets déterministes . Comme décrit dans le paragraphe suivant, la plupart des ressources (hormis la mémoire, qui est abondante et peut être recyclée assez lentement) ne sont pas tenues de faire l'objet d'une durée de vie dans ces langues. Il existe quelques autres cas d'utilisation, mais ils sont rares dans mon expérience.

Votre deuxième point, la gestion manuelle des ressources, est à présent traité via une instruction qui effectue un nettoyage basé sur la portée, mais ne couple pas ce nettoyage à la durée de vie de l'objet (donc n'interagissant pas avec le GC et la sécurité de la mémoire). Ceci est usingen C #, withen Python, tryavec les ressources dans les versions récentes de Java.


la source
1
Cela n'explique pas pourquoi les modèles non déterministes tels que la GC devraient être supérieurs aux modèles déterministes. usingles déclarations ne sont possibles que localement. Il est impossible de nettoyer les ressources contenues dans les variables membres de cette façon.
Philipp
8
@Philipp La propriété partagée pour tout est un GC, mais très pauvre. Si vous prenez le mot "propriété partagée" pour impliquer le comptage des références, dites-le-bien, mais conservez la discussion sur les cycles dans les commentaires sur la réponse de Amon. Je ne suis pas sûr non plus que le comptage des références soit déterministe au sens où OP s'intéresse (les objets sont libérés le plus tôt possible, cycles d'escompte, mais vous ne pouvez souvent pas savoir quand c'est en regardant le programme). De plus, le décompte des tâches pour tout est lent, beaucoup plus lent qu'un GC de traçage moderne.
16
usingest une blague par rapport à RAII, juste pour que vous sachiez.
DeadMG
3
@ Philippe s'il vous plaît décrire votre métrique pour "supérieur". Il est vrai que la gestion manuelle de la mémoire est plus rapide au moment de l’exécution pour gérer la gestion de la mémoire. Toutefois, le coût des logiciels ne peut pas être évalué uniquement sur le temps que le processeur consacre à la gestion de la mémoire.
ARts
2
@ArTs: Je ne serais même pas nécessairement d'accord avec cela. RAII vient avec l'exigence qu'un objet doit être détruit car il laisse la portée. Une boucle est donc nécessaire pour effectuer n destructions d’objets. Sous un GC générationnel moderne, ces destructions pourraient être différées jusqu'à la fin de la boucle, voire plus tard, et ne nécessiteraient qu'une seule opération pour détruire des centaines d'itérations de mémoire. Un GC peut être très très rapide dans ses bons cas.
Phoshi
14

RAII découle également de la gestion automatique de la mémoire de comptage de références, telle que celle utilisée par Perl. Bien que le comptage de références soit facile à mettre en œuvre, déterministe et assez performant, il ne peut pas traiter les références circulaires (elles provoquent des fuites), raison pour laquelle il n’est pas couramment utilisé.

Les langages récupérés ne peuvent pas utiliser directement RAII, mais offrent souvent une syntaxe avec un effet équivalent. En Java, nous avons l'instruction try-with-ressource

try (BufferedReader br = new BufferedReader(new FileReader(path))) { ... }

qui appelle automatiquement .close()la ressource en sortie de bloc. C # a l' IDisposableinterface, ce qui permet .Dispose()d'être appelé en laissant une using (...) { ... }déclaration. Python a l' withénoncé suivant:

with open(filename) as f:
    ...

qui fonctionne de manière similaire. Dans un tour intéressant à ce sujet, la méthode d'ouverture de fichier de Ruby reçoit un rappel. Une fois le rappel exécuté, le fichier est fermé.

File.open(name, mode) do |f|
    ...
end

Je pense que Node.js utilise la même stratégie.

Amon
la source
4
L'utilisation de fonctions d'ordre supérieur pour la gestion des ressources remonte bien avant Ruby. En Lisps, il est assez courant d’avoir, par exemple, des with-open-filehandlefonctions qui ouvrent le fichier, le cèdent à une fonction et, au retour de la fonction, referment le fichier.
Jörg W Mittag
4
L'argument de référence cyclique est assez courant, mais quelle est son importance? Les références cycliques peuvent être atténuées à l'aide d'indicateurs faibles si la propriété est claire.
Philipp
2
@Philipp Lorsque vous utilisez le comptage des références, la propriété n'est généralement pas claire. De plus, cette réponse parle des langues qui utilisent le comptage des références exclusivement et automatiquement, de sorte que les références faibles n'existent pas ou sont beaucoup plus difficiles à utiliser que les références fortes.
3
Les structures de données cycliques de @Philipp sont très rares, à moins que vous ne travailliez avec des graphiques compliqués. Les pointeurs faibles ne sont pas utiles dans un graphe d'objet cyclique général, bien qu'ils soient utiles dans des cas plus courants tels que les pointeurs parents dans une arborescence. Une bonne solution consiste à conserver un objet de contexte qui représente la référence à l'ensemble du graphique et gère la destruction. Le recomptage n'est pas un dealbraker, mais il nécessite que le programmeur soit très conscient de ses restrictions. C'est-à-dire que son coût cognitif est légèrement supérieur à celui de la GC.
amon
1
Une raison importante pour laquelle le comptage des références est rarement utilisé est qu’il est souvent plus lent que GC, malgré sa simplicité.
Rufflewind
14

À mon avis, l’avantage le plus convaincant du ramassage des ordures est qu’il permet la composition . La correction de la gestion de la mémoire est une propriété locale dans un environnement de récupération. Vous pouvez examiner chaque partie séparément et déterminer si elle peut perdre de la mémoire. Combinez un nombre quelconque de parties correctes en mémoire et elles restent correctes.

Lorsque vous comptez sur le comptage de références, vous perdez cette propriété. Si votre application peut perdre de la mémoire, cela devient une propriété globale de toute l'application avec un comptage de références. Chaque nouvelle interaction entre les pièces a la possibilité d’utiliser la mauvaise propriété et de casser la gestion de la mémoire.

Cela a un effet très visible sur la conception des programmes dans les différentes langues. Les programmes dans les langages GC ont tendance à être un peu plus riches en objets avec beaucoup d'interactions, alors que dans les langages sans GC, on préfère les parties structurées avec des interactions strictement contrôlées et limitées entre elles.

Patrick
la source
1
La correction ne peut être composée que si les objets ne contiennent que des références pour leur propre compte, et non pour le compte des cibles de ces références. Une fois que des éléments tels que des notifications entrent dans le mélange (Bob fait référence à Joe car Joe a demandé à Bob de l'informer quand quelque chose s'est passé et Bob a promis de le faire, mais Bob ne se soucie pas de Joe sinon), la correction de GC nécessite souvent une gestion des ressources étendue. [implémenté manuellement dans de nombreux cas, car les systèmes GC ne disposent pas de l'automatisation C ++].
Supercat
@supercat: "L'exactitude de la GC nécessite souvent une gestion des ressources étendue". Hein? La portée n'existe que dans le code source et GC n'existe qu'au moment de l'exécution (et est donc totalement inconscient de l'existence de la portée).
Jon Harrop
@JonHarrop: J'utilisais le terme "scope" dans le même sens qu'un "pointeur" en C ++ [la durée de vie de l'objet devrait être celle du conteneur le contenant], car c'est ce que suppose la question d'origine. Mon argument est que les objets créent des références potentiellement longues à eux-mêmes à des fins telles que la réception d'événements peut ne pas être composable dans un système purement GC. Pour être correct, certaines références doivent être fortes et certaines références doivent être faibles, et quelles références doivent être, lesquelles dépendront de la manière dont un objet est utilisé. Par exemple ...
Supercat
... supposons que les objets Fred et Barney s'inscrivent pour recevoir une notification chaque fois que quelque chose dans un certain répertoire est modifié. Le gestionnaire de Fred ne fait qu'incrémenter un compteur dont il peut signaler la valeur sur demande, mais pour lequel il n'a pas d'autre utilisation. Le gestionnaire de Barney fera apparaître une nouvelle fenêtre si un certain fichier est modifié. Pour être correct, Fred devrait être inscrit avec un événement faible, mais celui de Barney devrait être fort, mais l’objet timer ne pourra pas le savoir.
Supercat
@supercat: C'est vrai. Je ne dirais pas que cela se produit "souvent". Je ne l'ai rencontré qu'une fois en 30 ans de programmation.
Jon Harrop
7

Les fermetures sont une caractéristique essentielle de pratiquement toutes les langues modernes. Ils sont très faciles à implémenter avec GC et très difficiles (bien que pas impossibles) à utiliser correctement RAII, car l’une de leurs principales caractéristiques est qu’ils vous permettent d’abstraire sur toute la durée de vie de vos variables!

C ++ ne les a obtenus que 40 ans après les autres, et il a fallu beaucoup de travail acharné de la part de personnes intelligentes pour les obtenir. En revanche, de nombreux langages de script conçus et implémentés par des personnes n'ayant aucune connaissance en conception et implémentation de langages de programmation en sont dotés.

Jörg W Mittag
la source
9
Je ne pense pas que les fermetures en C ++ soient un bon exemple. Les lambdas de C ++ 11 ne sont que du sucre syntaxique pour les classes de foncteurs (qui précèdent considérablement C ++ 11), et sont tout aussi dangereux pour la mémoire: vous obtenez tout simplement UB, un peu comme si vous conserviez une référence plus longue que valide. Le fait qu’ils soient apparus avec 40 ans de retard est dû à la reconnaissance tardive de la PF, et non à la recherche de moyens de le rendre sûr. Et bien que leur conception fût certainement une tâche énorme, je doute que l'essentiel de l'effort ait été consacré à des considérations de durée de vie.
Je suis d’accord avec Delnan: le C ++ n’a pas eu les fermetures correctes: vous devez les programmer très soigneusement si vous ne voulez pas obtenir de fichier core lorsque vous les invoquez.
Giorgio
2
@delnan: capture par référence Les lambda ont très intentionnellement cette [&]syntaxe. Tout programmeur C ++ associe déjà le &signe à des références et connaît les références obsolètes.
MSalters
2
@MSalters Quel est votre point de vue? J'ai dessiné la connexion de référence moi-même. Je n'ai pas dit que les lambdas C ++ étaient exceptionnellement dangereux, j'ai dit qu'ils étaient aussi dangereux que les références. Je n'ai pas soutenu que les lambdas C ++ sont mauvais, j'ai plaidé contre l'allégation de cette réponse (le C ++ a obtenu des fermetures très tard, car il fallait trouver comment le faire correctement).
5
  1. SBMM rend les programmes plus déterministes (vous pouvez dire exactement quand un objet est détruit);

Pour la plupart des programmeurs, le système d'exploitation n'est pas déterministe, leur allocateur de mémoire n'est pas déterministe et la plupart des programmes qu'ils écrivent sont concurrents et, par conséquent, intrinsèquement non déterministes. Ajouter la contrainte selon laquelle un destructeur est appelé exactement à la fin de la portée plutôt que légèrement avant ou légèrement après n'est pas un avantage pratique significatif pour la grande majorité des programmeurs.

  1. dans les langues qui utilisent GC, vous devez souvent gérer manuellement les ressources (voir la section Fermeture de fichiers en Java, par exemple), ce qui va en partie à l’encontre de l’objet de GC et est également sujet à des erreurs;

Voir usingen C # et useen F #.

  1. La mémoire de tas peut aussi (très élégamment, imo) être liée à la portée (voir std :: shared_ptr en C ++).

En d'autres termes, vous pouvez prendre le tas qui est une solution à usage général et le changer pour ne fonctionner que dans un cas spécifique qui limite sérieusement. C'est vrai, bien sûr, mais inutile.

Pourquoi SBMM n'est-il pas plus utilisé? Quels sont ses inconvénients?

SBMM limite ce que vous pouvez faire:

  1. SBMM crée le problème du funarg ascendant avec les fermetures lexicales de première classe, raison pour laquelle les fermetures sont populaires et faciles à utiliser dans des langages tels que C # mais rares et délicates en C ++. Notez qu'il existe une tendance générale vers l'utilisation de constructions fonctionnelles dans la programmation.

  2. SBMM nécessite des destructeurs et ils empêchent les appels finaux en ajoutant du travail supplémentaire à effectuer avant le retour d'une fonction. Les appels de queue sont utiles pour les machines à états extensibles et sont fournis par des éléments tels que .NET.

  3. Certaines structures de données et certains algorithmes sont notoirement difficiles à mettre en œuvre avec SBMM. Fondamentalement, partout où les cycles se produisent naturellement. Plus particulièrement, les algorithmes de graphes. Vous finissez par écrire votre propre GC.

  4. La programmation simultanée est plus difficile parce que le flux de contrôle et, par conséquent, la durée de vie des objets sont intrinsèquement non déterministes ici. Les solutions pratiques dans les systèmes de transmission de messages ont tendance à être une copie en profondeur des messages et l'utilisation de durées de vie excessivement longues.

  5. SBMM conserve les objets en vie jusqu'à la fin de leur portée dans le code source, ce qui est souvent plus long que nécessaire et peut être beaucoup plus long que nécessaire. Cela augmente la quantité de déchets flottants (objets inaccessibles en attente de recyclage). En revanche, le suivi de la récupération de place a tendance à libérer des objets peu de temps après la disparition de la dernière référence, ce qui peut être beaucoup plus tôt. Voir Mythes de gestion de la mémoire: rapidité .

SBMM est tellement contraignant que les programmeurs ont besoin d’une issue de secours pour les situations dans lesquelles des durées de vie ne peuvent pas être imbriquées. En C ++, shared_ptroffre une issue de secours, mais elle peut être environ 10 fois plus lente que le traçage de la récupération de place . Donc, utiliser SBMM au lieu de GC mettrait la plupart des gens mal pris la plupart du temps. Cela ne veut cependant pas dire que c'est inutile. SBMM est toujours utile dans le contexte des systèmes et de la programmation intégrée où les ressources sont limitées.

FWIW, vous voudrez peut-être consulter Forth et Ada et vous renseigner sur le travail de Nicolas Wirth.

Jon Harrop
la source
1
Si vous dites quels éléments je pourrais peut-être élaborer ou citer des articles.
Jon Harrop
2
Quelle est la pertinence d’être 10 fois plus lent dans quelques rares cas d’utilisation plutôt que d’être omniprésent dans tous les cas d’utilisation? C ++ a unique_ptr et, dans la plupart des cas, suffisant. A côté de cela, plutôt que d'attaquer RAII par le biais de C ++ (un langage que beaucoup aiment à haïr pour être un langage archaïque), si vous allez attaquer RAII par le biais d'une langue, essayez un jeune frère de la famille RAII, Rust par exemple. Rust a tout à fait raison sur le fait que C ++ s'est trompé alors que la plupart des choses ont bien fonctionné. En outre, "utiliser" vous permet d'obtenir un nombre très limité de cas d'utilisation et ignore la composition.
user1703394
2
"Quelle est la pertinence d’être 10 fois plus lent dans quelques rares cas d’utilisation plutôt que d’être omniprésent dans tous les cas d’utilisation?". Tout d’abord, c’est un argument circulaire: il shared_ptrn’est que rare en C ++, car il est très lent. Deuxièmement, il s’agit d’une comparaison de pommes et d’oranges (comme l’a déjà mentionné l’article cité précédemment), car elle shared_ptrest beaucoup plus lente que la production en GC. Troisièmement, les GC ne sont pas omniprésents et sont évités dans des logiciels tels que LMax et le moteur FIX de Rapid Addition.
Jon Harrop
1
@Jon Harrop, si vous ne m'avez pas éclairé, s'il vous plaît. Quelle recette magique utilisez-vous depuis plus de 30 ans pour atténuer les effets transitifs de l’utilisation de ressources en profondeur? Sans une telle recette magique après plus de 30 ans, je ne pouvais que conclure que vous deviez avoir mal attribué le fait d’être mordu par elle pour d’autres causes.
user1703394 le
1
@Jon Harrop, shared_ptr n'est pas rare en raison de sa lenteur, de sa raison pour laquelle dans un système bien conçu, le besoin de «propriété partagée» est rare.
user1703394
4

En regardant un indice de popularité comme TIOBE (ce qui est discutable, bien sûr, mais je suppose que pour votre genre de question, vous pouvez l'utiliser), vous voyez d'abord qu'environ 50% des 20 meilleurs sont des "langages de script" ou des "dialectes SQL ", où la" facilité d'utilisation "et les moyens d'abstraction ont beaucoup plus d'importance que les comportements déterministes. Parmi les langues "compilées" restantes, il existe environ 50% des langues avec SBMM et environ 50% sans. Ainsi, lorsque vous retirez les langages de script de votre calcul, je dirais que votre hypothèse est tout simplement fausse. Parmi les langages compilés, ceux avec SBMM sont aussi populaires que ceux sans.

Doc Brown
la source
1
En quoi la "facilité d'utilisation" est-elle différente du déterminisme? Un langage déterministe ne devrait-il pas être considéré comme plus facile à utiliser qu'un langage non déterministe?
Philipp
2
@Philipp Seule la chose qui est déterministe ou qui compte vraiment. La durée de vie d'un objet n'a pas d'importance en soi (bien que C ++ et ses amis lient beaucoup de choses qui importent à la durée de vie, car elles le peuvent). Lorsqu'un objet inaccessible est libéré n'a pas d'importance, car, par définition, vous ne l'utilisez plus.
Une dernière chose, divers "langages de script" tels que Perl et Python utilisent également le comptage de références comme moyen principal de gestion de la mémoire.
Philipp
1
@Philipp Au moins dans le monde Python, ceci est considéré comme un détail d'implémentation de CPython, et non comme une propriété du langage (et pratiquement toutes les autres implémentations évitent de compter de nouveau). De plus, je dirais que le comptage de références sans retrait optionnel avec cycle de sauvegarde GC ne peut être qualifié de SBMM ou de RAII. En fait, vous auriez du mal à trouver des promoteurs RAII qui considèrent ce style de gestion de la mémoire comme comparable à celui de RAII (principalement parce que ce n'est pas le cas, les cycles n'importe où peuvent empêcher une désallocation rapide n'importe où dans le programme).
3

Un avantage majeur d'un système de GC, que personne n'a encore mentionné, est qu'une référence dans un système de GC conserve son identité tant qu'elle existe . Si on appelle IDisposable.Dispose(.NET) ouAutoCloseable.Close (Java) sur un objet alors que des copies de la référence existent, ces copies continueront à faire référence au même objet. L'objet ne sera plus utile pour rien, mais les tentatives d'utilisation auront un comportement prévisible contrôlé par l'objet lui-même. En revanche, en C ++, si le code appelle deleteun objet et essaie de l'utiliser ultérieurement, tout l'état du système devient totalement indéfini.

Une autre chose importante à noter est que la gestion de la mémoire basée sur la portée fonctionne très bien pour les objets avec une propriété clairement définie. Cela fonctionne beaucoup moins bien, et parfois même carrément mal, avec des objets qui n’ont pas de propriété définie. En général, les objets mutables doivent avoir des propriétaires, alors que les objets immuables n'en ont pas besoin, mais il y a une erreur: il est très courant que le code utilise une instance de types mutables pour contenir des données immuables, en s'assurant qu'aucune référence ne sera exposée à code qui pourrait muter l'instance. Dans un tel scénario, les instances de la classe mutable peuvent être partagées entre plusieurs objets immuables et ne doivent donc pas être clairement définies.

supercat
la source
4
La propriété à laquelle vous faites référence dans la première moitié est la sécurité de la mémoire. Même si un CPG est un moyen très simple d’atteindre la sécurité de la mémoire, un GC n’est pas nécessaire: regardez Rust pour un exemple bien fait.
@delnan: Quand je regarde rust-lang.org, mon navigateur ne semble pas pouvoir naviguer utilement à partir de là. Où devrais-je chercher plus d'informations? Mon impression est que la sécurité de la mémoire sans GC impose certaines restrictions aux structures de données qui peuvent ne pas correspondre à tout ce qu'une application peut devoir faire, mais je serais heureux de me tromper.
Supercat
1
Je ne connais pas un seul (ou même un petit ensemble) de bonnes références pour cela; Ma connaissance de Rust s’est accumulée au cours des deux dernières années au cours de la lecture de la liste de diffusion (et de tout ce qui y est lié, notamment divers tutoriels, blogs de conception de langage, problèmes github, ThisWeekInRust, etc.). Pour répondre brièvement à votre impression: oui, chaque construction sécurisée impose (nécessairement) des restrictions, mais pour quasiment tout morceau de code sécurisé en mémoire, une construction sécurisée appropriée existe ou peut être écrite. Les plus répandus existent déjà en langage et en stdlib, tous les autres peuvent être écrits en code utilisateur.
@delnan: Rust nécessite-t-il des mises à jour interdépendantes aux compteurs de références ou dispose-t-il d'un autre moyen de gérer des objets immuables (ou des objets mutables enveloppés de manière immuable) qui n'ont pas de propriété définitive? Rust a-t-il un concept de pointeurs "propriétaires" et "non propriétaires"? Je me souviens d'un article sur les pointeurs "Xonor" qui traitait de l'idée que les objets ayant une seule référence les "possèdent", et d'autres références qui ne le sont pas; lorsque la référence "propriétaire" sort de son champ d'application, toutes les références non propriétaires deviennent des références à des objets morts et sont identifiables en tant que telles ...
supercat
1
Je ne pense pas que les commentaires de Stack Exchange soient le bon moyen de faire le tour d’une langue. Si vous êtes toujours intéressé, vous pouvez aller directement à la source (#rust IRC, liste de diffusion Rust-Dev, etc.) et / ou me contacter avec un forum de discussion (vous devriez pouvoir en créer un).
-2

Tout d’abord, il est très important de comprendre que l’assimilation de RAII à SBMM. ou même à SBRM. Une des qualités les plus essentielles (et les moins connues ou les moins appréciées) de RAII est le fait qu’elle «fait de la ressource» une propriété qui n’EST PAS transitive en composition.

Le billet de blog suivant aborde cet aspect important de la RAII et le compare à un arrangement de ressources dans des langages GCed qui utilisent un GC non déterministe.

http://minorfs.wordpress.com/2011/04/29/why-garbage-collection-is-anti-productive/

Il est important de noter que bien que RAII soit principalement utilisé en C ++, Python (enfin la version non basée sur VM) possède des destructeurs et des GC déterministes qui permettent d’utiliser RAII avec GC. Le meilleur des deux mondes s'il en était.

utilisateur1703394
la source
1
-1 C'est l'un des pires articles que j'ai jamais lu.
Jon Harrop
1
Le problème dans les langues n’est pas qu’ils supportent le GC, mais qu’ils abandonnent RAII. Il n'y a aucune raison qu'un langage / framework ne puisse pas supporter les deux.
Supercat
1
@Jon Harrop, pourriez-vous élaborer. Parmi les revendications formulées dans l'article, y a-t-il même une des 3 premières revendications qui ne tient pas? Je pense que vous pouvez être en désaccord sur l'allégation de productivité, mais les 3 autres allégations sont tout à fait valables. Le plus important est le premier sur la transitivité d'être une ressource.
user1703394
2
@ user1703394: Tout d'abord, l'intégralité de l'article est basée sur un "langage GCed", qui n'a rien à voir avec le ramassage des ordures. Deuxièmement, il blâme le ramassage des ordures alors qu'en fait, les erreurs relèvent de la programmation orientée objet. Enfin, son argument est 10 ans trop tard. La grande majorité des programmeurs ont déjà modernisé leurs langages avec des ordures ménagères, précisément parce qu'ils offrent une productivité bien supérieure.
Jon Harrop
1
Ses exemples concrets (RAM, poignées de fichier ouvertes, verrous, threads) sont assez révélateurs. J'ai du mal à me rappeler la dernière fois que j'ai dû écrire du code qui traitait directement de ces problèmes. Avec la RAM, le GC automatise tout. Avec File.ReadLines file |> Seq.lengthles descripteurs de fichier, j'écris du code comme à l' endroit où les abstractions gèrent la fermeture pour moi. Serrures et threads que j'ai remplacés par .NET Tasket F # MailboxProcessor. Cet ensemble "nous avons explosé la quantité de gestion manuelle des ressources" est un non-sens total.
Jon Harrop