78 votes

RAII vs. Garbage Collector

J'ai récemment regardé un grand discours, Herb Sutter à propos de "Fuite de C++ Libre..." à CppCon 2016, où il a parlé de l'utilisation des pointeurs intelligents pour mettre en œuvre RAII (acquisition de Ressources est d'initialisation) - Concepts et la façon dont ils résolvent la plupart des problèmes de fuites de mémoire.

Maintenant, je me demandais. Si je suivre strictement RAII règles, ce qui semble être une bonne chose, pourquoi serait-ce différent d'avoir un garbage collector en C++? Je sais qu'avec RAII le programmeur est en plein contrôle de lorsque les ressources sont libérées de nouveau, mais est-ce que dans tous les cas bénéfique juste d'avoir un garbage collector? Serait-il vraiment moins efficace? J'ai même entendu que le fait d'avoir un garbage collector peut être plus efficace, car il peut libérer des plus gros morceaux de la mémoire à la fois au lieu de libérer la mémoire des petites pièces de partout dans le code.

66voto

utnapistim Points 12060

Si je suivre strictement RAII règles, ce qui semble être une bonne chose, pourquoi serait-ce différent d'avoir un garbage collector en C++?

Alors que de traiter avec des allocations, ils le font de manière complètement différentes manières. Si vous êtes faisant référence à une table comme celle de Java, qui ajoute ses propres frais généraux, enlève le déterminisme de la ressource processus de libération et de poignées de références circulaires.

Vous pouvez mettre en œuvre GC, bien que pour des cas particuliers, avec beaucoup de différentes caractéristiques de performance. J'ai mis en place une fois pour la fermeture des connexions socket, dans une haute performance/haute-débit serveur (juste appeler le support à proximité de l'API a pris trop de temps et complètement foireuse les performances de débit). Cela impliquait pas de mémoire, mais les connexions réseau, et pas de dépendance cyclique de la manipulation.

Je sais qu'avec RAII le programmeur est en plein contrôle de lorsque les ressources sont libérées de nouveau, mais est-ce que dans tous les cas bénéfique juste d'avoir un garbage collector?

Ce déterminisme est une fonctionnalité que GC n'a tout simplement pas permettre. Parfois, vous voulez être en mesure de savoir que, après un certain point, une opération de nettoyage a été effectué (suppression d'un fichier temporaire, la fermeture d'une connexion réseau, etc).

Dans de tels cas GC ne coupe pas elle qui est la raison en C# (par exemple) vous avez l' IDisposable interface.

J'ai même entendu que le fait d'avoir un garbage collector peut être plus efficace, car il peut libérer des plus gros morceaux de la mémoire à la fois au lieu de libérer la mémoire des petites pièces de partout dans le code.

Peut être ... dépend de la mise en œuvre.

38voto

Yakk Points 31636

La collecte des ordures résout certaines classes de problèmes de ressources que RAII ne peut pas résoudre. En gros, ça se résume à des dépendances circulaires où vous n'avez pas d'identifier le cycle avant de la main.

Ce qui donne deux avantages. Tout d'abord, il va y avoir certains types de problème que RAII ne peut pas résoudre. Ce sont, à mon expérience, rare.

Le plus grand est qu'il permet au programmeur d'être paresseux et de ne pas les soins sur la mémoire de ressources de la durée de vie et de certaines autres ressources que vous n'avez pas l'esprit retard de nettoyage sur. Lorsque vous n'avez pas de soins sur certains types de problèmes, vous pouvez prendre soin de plus au sujet d'autres problèmes. Cela permet de vous concentrer sur les parties de votre problème, vous voulez vous concentrer sur.

L'inconvénient est que, sans RAII, la gestion des ressources dont la durée de vie que vous voulez contrainte est dur. GC langues essentiellement de réduire vous soit extrêmement simple portée lié à la durée de vie ou de vous obliger à faire la gestion des ressources manuellement, comme en C, avec manuellement en indiquant que vous avez terminé avec une ressource. Leur durée de vie objet système est fortement liée à la GC, et ne fonctionne pas bien pour une gestion du cycle de vie d'un grand complexe (pourtant, cycle libre) des systèmes.

Pour être juste, la gestion des ressources en C++ prend beaucoup de travail à faire correctement dans ces grands complexes (pourtant, cycle libre) des systèmes. C# et langues similaires juste faire un peu plus difficile, en échange, ils font l'affaire facile facile.

La plupart des GC implémentations également les forces de la non-localité à part entière classes; la création d'contigus des coussins en général des objets, ou de la composition générale des objets en un seul objet, n'est pas quelque chose que la plupart des GC implémentations de faire simple. D'autre part, C# permet de créer de la valeur type structs avec peu de capacités limitées. Dans l'ère actuelle de l'architecture du PROCESSEUR, de la mémoire cache amitié est la clé, et l'absence de localité GC forces est un lourd fardeau. Que ces langues ont un bytecode d'exécution pour la plupart, en théorie, le JIT de l'environnement pourraient se déplacer de données couramment utilisés ensemble, mais le plus souvent, vous obtenez juste un uniforme de la perte de performance due à de fréquentes erreurs de la mémoire cache par rapport à C++.

Le dernier problème de la cg, c'est que la libération est indéterminée, et peut parfois entraîner des problèmes de performances. Moderne GCs rendre cela moins d'un problème qu'il ne l'a été dans le passé.

14voto

Basile Starynkevitch Points 67055

Notez que RAII est un langage de programmation, tandis que la GC est une gestion de la mémoire technique. Nous sommes donc à comparer des pommes avec des oranges.

Mais nous pouvons restreindre l'RAII pour sa gestion de la mémoire aspects seulement et de les comparer à GC techniques.

La principale différence entre les dits RAII mémoire fondée sur les techniques de gestion (qui a vraiment les moyens de comptage de référence, au moins quand on considère les ressources de mémoire et d'ignorer les autres, tels que les fichiers) et une véritable collecte des ordures techniques de la manipulation de la circulaire références (pour les graphes cycliques).

Avec le comptage de référence, vous avez besoin de code spécialement pour eux (à l'aide de références faibles ou d'autres trucs).

Dans de nombreux cas ( std::vector<std::map<std::string,int>>) le comptage de référence est implicite (puisqu'il ne peut être que 0 ou 1) et est pratiquement omis, mais le constructeur et le destructeur des fonctions essentielles à RAII) se comportent comme si il y avait une référence de comptage de bits (ce qui est pratiquement absent). En std::shared_ptr il y a un véritable compteur de référence. Mais la mémoire est toujours implicitement gérés manuellement (avec new et delete déclenché à l'intérieur des constructeurs et destructeurs), mais que "implicite" delete (dans les destructeurs) donne l'illusion de la gestion automatique de la mémoire. Toutefois, les appels à l' new et delete encore arriver (et ils coûtent du temps).

BTW le GC de la mise en œuvre peut (souvent) de la poignée de la circularité d'une certaine manière, mais vous laissez de la charge de la GC (par exemple, lire à propos de l' Cheney de l'algorithme).

Certains algorithmes de GC (notamment intergénérationnelle de la copie de garbage collector) ne vous embêtez pas à la libération de la mémoire pour les individuels, des objets, elle est sortie en masse après la copie. Dans la pratique, l'Ocaml GC (ou le SBCL un) peut être plus rapide qu'une véritable C++ RAII style de programmation (pour certains, pas tous, type d'algorithmes).

Certains GC fournir finalisation (principalement utilisé pour gérer les non-mémoire de ressources externes comme les fichiers), mais vous aurez rarement l'utiliser (comme la plupart des valeurs de consommer uniquement des ressources de la mémoire). L'inconvénient est que l'achèvement du programme n'offre pas les délais de garantie. Pratiquement parlant, un programme à l'aide de la finalisation est en l'utilisant comme un dernier recours (par exemple, la fermeture de fichiers doivent encore se produire plus ou moins explicitement à l'extérieur de finalisation, et aussi avec eux).

Vous pouvez avoir de fuites de mémoire de la cg (et aussi avec RAII, au moins lorsque mal utilisés), par exemple, lorsqu'une valeur est conservée dans une variable ou un champ, mais ne seront jamais utilisées à l'avenir. Ils se produisent moins souvent.

Je recommande la lecture de la collecte des ordures manuel.

Dans votre code C++, vous pouvez utiliser Boehm GC ou Ravenbrook des DÉPUTÉS ou votre propre code de traçage garbage collector. Bien sûr, à l'aide d'un GC est un compromis (il y en a certains inconvénients, par exemple, le non-déterminisme, le manque de synchronisation des garanties, etc...).

Je ne pense pas que RAII est la meilleure façon de traiter avec la mémoire dans tous les cas. À plusieurs reprises, le codage de votre programme dans un véritable et efficace GC implémentations (pensez à Ocaml ou SBCL) peut être plus simple (à développer) et plus rapide (pour exécution) que le codage avec fantaisie RAII style en C++17. Dans d'autres cas, il ne l'est pas. YMMV.

Par exemple, si l'on code un interpréteur Scheme en C++17 avec le plus chic RAII style, vous auriez encore besoin de code (ou d'utiliser) une explicite GC à l'intérieur (à cause d'un Régime de tas a circularités). Et la plupart des assistants de preuve sont codés en GC-ed langues, souvent fonctionnels, (le seul que je connaisse qui est codé en C++ est Maigre) pour de bonnes raisons.

BTW, je suis intéressé à trouver un tel C++17 de la mise en œuvre de Schéma (mais de moins en moins intéressé à coder moi-même), de préférence avec quelques multi-threading capacité.

14voto

Cort Ammon Points 1584

RAII et GC résoudre des problèmes dans des directions complètement différentes. Ils sont complètement différents, malgré ce que certains disent.

Les deux traitent de la question de la gestion des ressources est dur. La Collecte des ordures de la résoudre en faisant en sorte que le développeur n'a pas besoin de payer autant d'attention à la gestion de ces ressources. RAII résout en le rendant plus facile pour les développeurs de prêter attention à la gestion de leurs ressources. Toute personne qui dit qu'ils font la même chose a quelque chose à vous vendre.

Si vous regardez les tendances récentes dans les langues, vous voyez les deux approches utilisées dans la même langue, parce que, franchement, vous avez vraiment besoin des deux côtés de l'énigme. Vous en avez vu beaucoup de langues qui utilisent la collecte des ordures de toutes sortes, de sorte que vous n'avez pas à payer l'attention de la plupart des objets, et ces langues offrent également RAII solutions (comme python with opérateur) pour le temps que vous voulez vraiment faire attention à eux.

  • C++ offre RAII par les constructeurs/destructeurs et GC par shared_ptr (Si je peut en faire l'argument que les compteurs refcount et GC sont dans la même classe de solutions parce qu'ils sont tous deux conçus pour vous aider à ne pas besoin de prêter attention à la durée de vie)
  • Python propose RAII par with et GC par le biais d'un système de compteurs refcount plus d'un garbage collector
  • C# offre RAII par IDisposable et using et GC par l'intermédiaire d'un générationnelle garbage collector

Les modèles sont à se propager dans toutes les langues.

10voto

tty6 Points 675

L'un des problème sur les ramasseurs d'ordures, c'est qu'il est difficile de prédire les performances du programme.

Avec RAII vous savez qu'à l'heure exacte de la ressource passe hors de portée vous effacer la mémoire et il faudra un certain temps. Mais si vous n'êtes pas un maître de garbage collector paramètres vous ne pouvez pas prédire quand le nettoyage va se passer.

Par exemple: nettoyage d'un tas de petits objets qui peut être fait de manière plus efficace avec le GC, car il peut gratuit gros morceau, mais il ne sera pas rapide, et il est difficile de prédire le moment où va se produire et, à cause de "gros morceau de nettoyage", il faudra un certain temps processeur et peut affecter votre rendement du programme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X