Je ne pose pas cette question en raison des avantages de la collecte des ordures tout d'abord. Ma principale raison de demander ceci est que je sais que Bjarne Stroustrup a dit que C ++ aura un ramasse-miettes à un moment donné.
Cela dit, pourquoi n'a-t-il pas été ajouté? Il existe déjà des récupérateurs de place pour C ++. Est-ce juste une de ces choses de type «plus facile à dire qu'à faire»? Ou y a-t-il d'autres raisons pour lesquelles il n'a pas été ajouté (et ne sera pas ajouté en C ++ 11)?
Liens croisés:
Juste pour clarifier, je comprends les raisons pour lesquelles C ++ n'avait pas de garbage collector lors de sa création. Je me demande pourquoi le collecteur ne peut pas être ajouté.
c++
garbage-collection
c++11
Jason Baker
la source
la source
Réponses:
Un ramasse-miettes implicite aurait pu être ajouté, mais il n'a tout simplement pas été coupé. Probablement en raison non seulement des complications de mise en œuvre, mais aussi du fait que les gens ne sont pas parvenus à un consensus général assez rapidement.
Une citation de Bjarne Stroustrup lui-même:
Il y a une bonne discussion du sujet ici .
Aperçu général:
C ++ est très puissant et vous permet de faire presque n'importe quoi. Pour cette raison, il ne vous pousse pas automatiquement de nombreux éléments susceptibles d'avoir un impact sur les performances. La récupération de place peut être facilement implémentée avec des pointeurs intelligents (objets qui enveloppent les pointeurs avec un compte de référence, qui se suppriment automatiquement lorsque le compte de référence atteint 0).
C ++ a été construit avec des concurrents à l'esprit qui n'avaient pas de ramasse-miettes. L'efficacité était la principale préoccupation que C ++ devait repousser la critique par rapport à C et à d'autres.
Il existe 2 types de ramassage des ordures ...
Récupération de place explicite:
C ++ 0x aura la récupération de place via des pointeurs créés avec shared_ptr
Si vous le voulez, vous pouvez l'utiliser, si vous ne le voulez pas, vous n'êtes pas obligé de l'utiliser.
Vous pouvez actuellement utiliser boost: shared_ptr également si vous ne voulez pas attendre C ++ 0x.
Ramasse-miettes implicite:
Cependant, il n'a pas de récupération de place transparente. Ce sera un point focal pour les futures spécifications C ++.
Pourquoi Tr1 n'a pas de récupération de place implicite?
Il y avait beaucoup de choses que tr1 de C ++ 0x aurait dû avoir, Bjarne Stroustrup dans des interviews précédentes a déclaré que tr1 n'en avait pas autant qu'il l'aurait souhaité.
la source
smart_ptr's
? Comment feriez-vous une fourche de style Unix de bas niveau, avec un garbage collector sur le chemin? D'autres choses seraient affectées comme le filetage. Python a son verrou d'interpréteur global, principalement en raison de sa collecte des ordures (voir Cython). Gardez-le hors de C / C ++, merci.std::shared_ptr
) est les références cycliques, qui provoquent une fuite de mémoire. Par conséquent, vous devez utiliser soigneusementstd::weak_ptr
pour rompre les cycles, ce qui est désordonné. Le style de marquage et de balayage GC n'a pas ce problème. Il n'y a pas d'incompatibilité inhérente entre le threading / forking et le garbage collection. Java et C # ont tous deux un multithread préemptif hautes performances et un garbage collector. Il y a des problèmes avec les applications en temps réel et un garbage collector, car la plupart des garbage collector doivent arrêter le monde pour fonctionner.std::shared_ptr
) Est les références cycliques" et des performances horribles qui sont ironiques car de meilleures performances sont généralement la justification de l'utilisation de C ++ ... flyingfrogblog.blogspot.co.uk/2011/01/…Pour ajouter au débat ici.
Il existe des problèmes connus avec la récupération de place, et leur compréhension permet de comprendre pourquoi il n'y en a pas en C ++.
1. Performance?
La première plainte concerne souvent la performance, mais la plupart des gens ne réalisent pas vraiment de quoi ils parlent. Comme l'illustre
Martin Beckett
le problème, ce n'est peut-être pas la performance en soi, mais la prévisibilité de la performance.Il existe actuellement 2 familles de GC largement déployées:
Le
Mark And Sweep
est plus rapide (moins d'impact sur les performances globales) mais il souffre d'un syndrome de "gel du monde": c'est-à-dire lorsque le GC entre en action, tout le reste est arrêté jusqu'à ce que le GC ait fait son nettoyage. Si vous souhaitez construire un serveur qui répond en quelques millisecondes ... certaines transactions ne seront pas à la hauteur de vos attentes :)Le problème
Reference Counting
est différent: le comptage de références ajoute des frais généraux, en particulier dans les environnements multithreading car vous devez avoir un comptage atomique. De plus, il y a le problème des cycles de référence, vous avez donc besoin d'un algorithme intelligent pour détecter ces cycles et les éliminer (généralement mis en œuvre par un "gel du monde" aussi, bien que moins fréquent). En général, à ce jour, ce type (même s'il est normalement plus réactif ou plutôt gelant moins souvent) est plus lent que leMark And Sweep
.J'ai vu un article d'implémenteurs Eiffel qui essayaient d'implémenter un
Reference Counting
Garbage Collector qui aurait une performance globale similaire àMark And Sweep
sans l'aspect "Freeze The World". Il fallait un thread séparé pour le GC (typique). L'algorithme était un peu effrayant (à la fin) mais le document a fait un bon travail en introduisant les concepts un par un et en montrant l'évolution de l'algorithme de la version "simple" à la version à part entière. Lecture recommandée si seulement je pouvais remettre mes mains sur le fichier PDF ...2. L'acquisition de ressources est l'initialisation (RAII)
C'est un idiome courant en ce sens
C++
que vous encapsulerez la propriété des ressources dans un objet pour vous assurer qu'elles sont correctement libérées. Il est principalement utilisé pour la mémoire car nous n'avons pas de récupération de place, mais il est néanmoins utile dans de nombreuses autres situations:L'idée est de bien contrôler la durée de vie de l'objet:
Le problème du GC est que s'il aide avec le premier et garantit finalement que plus tard ... cet "ultime" peut ne pas être suffisant. Si vous libérez un verrou, vous aimeriez vraiment qu'il soit libéré maintenant, afin qu'il ne bloque plus aucun appel!
Les langues avec GC ont deux contournements:
using
construire ... mais il est explicite (faible) RAII en C ++ RAII est implicite de sorte que l'utilisateur NE PEUT PAS faire l'erreur sans le savoir (en omettant leusing
mot - clé)3. Pointeurs intelligents
Les pointeurs intelligents apparaissent souvent comme une solution miracle pour gérer la mémoire
C++
. Souvent, j'ai entendu: nous n'avons pas besoin de GC après tout, car nous avons des pointeurs intelligents.On ne peut plus se tromper.
Les pointeurs intelligents aident
auto_ptr
etunique_ptr
utilisent des concepts RAII, extrêmement utiles en effet. Ils sont si simples que vous pouvez les écrire vous-même assez facilement.Cependant, quand il faut partager la propriété, cela devient plus difficile: vous pouvez partager entre plusieurs threads et il y a quelques problèmes subtils avec la gestion du compte. Par conséquent, on va naturellement vers
shared_ptr
.C'est génial, c'est pour ça que Boost après tout, mais ce n'est pas une solution miracle. En fait, le principal problème
shared_ptr
est qu'il émule un GC implémenté parReference Counting
mais vous devez implémenter la détection de cycle par vous-même ... UrgBien sûr, il y a ce
weak_ptr
truc, mais j'ai malheureusement déjà vu des fuites de mémoire malgré l'utilisation de àshared_ptr
cause de ces cycles ... et lorsque vous êtes dans un environnement multi-thread, c'est extrêmement difficile à détecter!4. Quelle est la solution?
Il n'y a pas de solution miracle, mais comme toujours, c'est définitivement faisable. En l'absence de GC, il faut être clair sur la propriété:
weak_ptr
Donc en effet, ce serait génial d'avoir un GC ... mais ce n'est pas un problème trivial. Et en attendant, nous avons juste besoin de retrousser nos manches.
la source
Quel genre? Doit-il être optimisé pour les contrôleurs de lave-linge intégrés, les téléphones portables, les postes de travail ou les superordinateurs?
Doit-il prioriser la réactivité de l'interface graphique ou le chargement du serveur?
Doit-il utiliser beaucoup de mémoire ou beaucoup de CPU?
C / c ++ est utilisé dans trop de circonstances différentes. Je soupçonne que quelque chose comme booster les pointeurs intelligents sera suffisant pour la plupart des utilisateurs
Edit - Les ramasse-miettes automatiques ne sont pas tellement un problème de performances (vous pouvez toujours acheter plus de serveurs), c'est une question de performances prédictibles.
Ne pas savoir quand le GC va entrer en action, c'est comme employer un pilote de ligne narcoleptique, la plupart du temps ils sont formidables - mais quand vous avez vraiment besoin de réactivité!
la source
L'une des principales raisons pour lesquelles C ++ n'a pas intégré la récupération de place est qu'il est très difficile de faire fonctionner la récupération de place avec les destructeurs. Pour autant que je sache, personne ne sait vraiment vraiment comment le résoudre complètement. Il y a beaucoup de problèmes à régler:
Ce ne sont là que quelques-uns des problèmes rencontrés.
la source
Dispose
à un objet peut le rendre impossible, mais les références qui pointaient vers l'objet quand il était vivant continueront de le faire après sa mort. En revanche, dans les systèmes non GC, les objets peuvent être supprimés tant que des références existent, et il n'y a rarement aucune limite aux ravages qui peuvent être causés si l'une de ces références est utilisée.Bien que ce soit une vieille question, il y a encore un problème que je ne vois personne avoir résolu du tout: la collecte des ordures est presque impossible à spécifier.
En particulier, la norme C ++ prend bien soin de spécifier le langage en termes de comportement observable de l'extérieur, plutôt que de la façon dont l'implémentation réalise ce comportement. Dans le cas de la collecte des ordures, cependant, il n'y a pratiquement aucun comportement observable de l'extérieur.
L' idée générale de la récupération de place est qu'elle doit faire une tentative raisonnable pour garantir la réussite d'une allocation de mémoire. Malheureusement, il est essentiellement impossible de garantir que toute allocation de mémoire réussira, même si vous avez un garbage collector en fonctionnement. Cela est vrai dans une certaine mesure dans tous les cas, mais particulièrement dans le cas de C ++, car il n'est (probablement) pas possible d'utiliser un collecteur de copie (ou quelque chose de similaire) qui déplace les objets en mémoire pendant un cycle de collecte.
Si vous ne pouvez pas déplacer des objets, vous ne pouvez pas créer un seul espace mémoire contigu à partir duquel effectuer vos allocations - et cela signifie que votre tas (ou magasin gratuit, ou tout ce que vous préférez l'appeler) peut, et le fera probablement , se fragmentent avec le temps. Ceci, à son tour, peut empêcher une allocation de réussir, même s'il y a plus de mémoire disponible que la quantité demandée.
Bien qu'il soit possible de trouver une garantie qui dit (en substance) que si vous répétez exactement le même modèle d'allocation à plusieurs reprises, et qu'il a réussi la première fois, il continuera à réussir lors des itérations suivantes, à condition que la mémoire allouée est devenu inaccessible entre les itérations. C'est une garantie si faible qu'elle est essentiellement inutile, mais je ne vois aucun espoir raisonnable de la renforcer.
Néanmoins, il est plus fort que ce qui a été proposé pour C ++. La proposition précédente [avertissement: PDF] (qui a été supprimée) ne garantissait rien du tout. Dans 28 pages de proposition, ce que vous avez obtenu en termes de comportement observable de l'extérieur était une seule note (non normative) disant:
Du moins pour moi, cela soulève une sérieuse question de retour sur investissement. Nous allons casser le code existant (personne ne sait exactement combien, mais certainement pas mal), imposer de nouvelles exigences sur les implémentations et de nouvelles restrictions sur le code, et ce que nous obtenons en retour est très probablement rien du tout?
Même au mieux, nous obtenons des programmes qui, basés sur tests avec Java , nécessiteront probablement environ six fois plus de mémoire pour fonctionner à la même vitesse qu'ils le font actuellement. Pire encore, la collecte des ordures faisait partie de Java depuis le début - C ++ impose suffisamment de restrictions au récupérateur de déchets pour qu'il aura certainement un rapport coûts / avantages encore pire (même si nous allons au-delà de ce que la proposition garantit et supposons qu'il y en aura). certains avantages).
Je résumerais la situation mathématiquement: c'est une situation complexe. Comme tout mathématicien le sait, un nombre complexe se compose de deux parties: réelle et imaginaire. Il me semble que nous avons ici des coûts qui sont réels, mais des avantages qui sont (au moins surtout) imaginaires.
la source
free
(où je veux direfree
analogue au langage C). Mais Java ne garantit jamais d'appeler les finaliseurs ou quelque chose comme ça. En fait, C ++ fait bien plus que Java pour exécuter les écritures de base de données de validation, le vidage des descripteurs de fichiers, etc. Java prétend avoir "GC", mais les développeurs Java doivent appeler méticuleusementclose()
tout le temps et ils doivent être très conscients de la gestion des ressources, en faisant attention de ne pas appelerclose()
trop tôt ou trop tard. C ++ nous en libère. ... (suite)try (Whatever w=...) {...}
résout (et vous obtenez un avertissement lorsque vous oubliez). Les autres sont également problématiques avec RAII. Appelerclose()
"tout le temps" signifie peut-être une fois par dizaines de milliers de lignes, donc ce n'est pas si mal, alors que la mémoire est allouée presque sur chaque ligne Java.La source: http://www.stroustrup.com/bs_faq.html#garbage-collection
Quant à savoir pourquoi il ne l'a pas intégré, si je me souviens bien, il a été inventé avant que GC ne soit la chose , et je ne pense pas que le langage aurait pu avoir GC pour plusieurs raisons (IE rétrocompatibilité avec C)
J'espère que cela t'aides.
la source
Stroustrup a fait de bons commentaires à ce sujet lors de la conférence Going Native 2013.
Passez à environ 25m50 dans cette vidéo . (Je recommanderais en fait de regarder la vidéo en entier, mais cela passe aux choses sur la collecte des ordures.)
Lorsque vous avez une langue vraiment géniale qui rend facile (et sûr, et prévisible, et facile à lire et facile à enseigner) pour traiter les objets et les valeurs de manière directe, en évitant l'utilisation (explicite) du tas, alors vous ne voulez même pas la collecte des ordures.
Avec le C ++ moderne, et les trucs que nous avons en C ++ 11, la récupération de place n'est plus souhaitable, sauf dans des circonstances limitées. En fait, même si un bon garbage collector est intégré à l'un des principaux compilateurs C ++, je pense qu'il ne sera pas utilisé très souvent. Il sera plus facile , pas plus difficile, d'éviter le GC.
Il montre cet exemple:
Ce n'est pas sûr en C ++. Mais c'est aussi dangereux en Java! En C ++, si la fonction revient tôt, le
delete
ne sera jamais appelé. Mais si vous aviez un ramasse-miettes complet, comme en Java, vous obtenez simplement une suggestion que l'objet sera détruit "à un moment donné dans le futur" ( mise à jour: c'est encore pire que cela. Java ne fonctionne paspromettre d'appeler le finaliseur jamais - il ne sera peut-être jamais appelé). Ce n'est pas suffisant si Gadget contient un descripteur de fichier ouvert, ou une connexion à une base de données, ou des données que vous avez mises en mémoire tampon pour être écrites dans une base de données à un stade ultérieur. Nous voulons que le gadget soit détruit dès qu'il est terminé, afin de libérer ces ressources dès que possible. Vous ne voulez pas que votre serveur de base de données se débat avec des milliers de connexions de base de données qui ne sont plus nécessaires - il ne sait pas que votre programme a fini de fonctionner.Alors, quelle est la solution? Il existe quelques approches. L'approche évidente, que vous utiliserez pour la grande majorité de vos objets est:
Cela prend moins de caractères à taper. Cela ne doit pas
new
gêner. Il ne vous oblige pas à taperGadget
deux fois. L'objet est détruit à la fin de la fonction. Si c'est ce que vous voulez, c'est très intuitif.Gadget
s se comportent commeint
oudouble
. Prévisible, facile à lire, facile à enseigner. Tout est une «valeur». Parfois une grande valeur, mais les valeurs sont plus faciles à enseigner parce que vous n'avez pas cette chose "d'action à distance" que vous obtenez avec des pointeurs (ou des références).La plupart des objets que vous créez sont destinés à être utilisés uniquement dans la fonction qui les a créés et peut-être passés en tant qu'entrées aux fonctions enfants. Le programmeur ne devrait pas avoir à penser à la «gestion de la mémoire» lorsqu'il retourne des objets, ou autrement partage des objets entre des parties largement séparées du logiciel.
La portée et la durée de vie sont importantes. La plupart du temps, c'est plus facile si la durée de vie est la même que la portée. C'est plus facile à comprendre et à enseigner. Lorsque vous voulez une durée de vie différente, il devrait être évident en lisant le code que vous faites cela, en utilisant
shared_ptr
par exemple. (Ou renvoyer des objets (volumineux) par valeur, en exploitant la sémantique de mouvement ouunique_ptr
.Cela peut sembler un problème d'efficacité. Et si je veux retourner un gadget
foo()
? La sémantique de mouvement de C ++ 11 facilite le retour de gros objets. Il suffit d'écrireGadget foo() { ... }
et cela fonctionnera et fonctionnera rapidement. Vous n'avez pas besoin de&&
vous embêter, renvoyez simplement les choses par valeur et le langage pourra souvent faire les optimisations nécessaires. (Même avant C ++ 03, les compilateurs ont remarquablement bien évité la copie inutile.)Comme Stroustrup l'a dit ailleurs dans la vidéo (paraphrase): "Seul un informaticien insisterait pour copier un objet, puis détruire l'original. (L'auditoire rit). Pourquoi ne pas simplement déplacer l'objet directement vers le nouvel emplacement? C'est ce que les humains (pas les informaticiens) s’attendent. "
Lorsque vous pouvez garantir qu'une seule copie d'un objet est nécessaire, il est beaucoup plus facile de comprendre la durée de vie de l'objet. Vous pouvez choisir la politique de durée de vie que vous souhaitez et la récupération de place est là si vous le souhaitez. Mais lorsque vous comprendrez les avantages des autres approches, vous constaterez que la collecte des ordures est au bas de votre liste de préférences.
Si cela ne fonctionne pas pour vous, vous pouvez utiliser
unique_ptr
, ou à défaut,shared_ptr
. Un C ++ 11 bien écrit est plus court, plus facile à lire et à enseigner que de nombreux autres langages en matière de gestion de la mémoire.la source
Gadget
ne demande rien d'autre pour faire quoi que ce soit en son nom, le code d'origine serait parfaitement sûr en Java si l'delete
instruction vide de sens (vers Java) était supprimée.shared_ptr<T>
spécialement lorsqu'ilT
est «ennuyeux». Il pourrait décider de ne pas gérer réellement un compteur de références pour ce type et d'utiliser plutôt GC. Cela permettrait au GC d'être utilisé sans que le développeur n'en ait besoin. Ashared_ptr
pourrait simplement être considéré comme un pointeur GC, pour convenirT
. Mais il y a des limites à cela, et cela ralentirait de nombreux programmes.string1=string2;
s'exécutera très rapidement quelle que soit la longueur de la chaîne (ce n'est littéralement rien de plus qu'un chargement de registre et un magasin de registres), et ne nécessite aucun verrouillage pour garantir que si l'instruction ci-dessus est exécutée alors qu'ellestring2
est en cours d'écriture,string1
conservera l'ancienne ou la nouvelle valeur, sans comportement indéfini).shared_ptr<String>
nécessite beaucoup de synchronisation en arrière-plan, et l'affectation d'unString
peut se comporter bizarrement si une variable est lue et écrite simultanément. Les cas où l'on voudrait écrire et lireString
simultanément ne sont pas très courants, mais peuvent survenir si, par exemple, un code souhaite rendre les rapports d'état en cours disponibles pour d'autres threads. En .NET et Java, de telles choses "fonctionnent" simplement.Parce que le C ++ moderne n'a pas besoin de garbage collection.
La réponse de Bjarne Stroustrup à la FAQ à ce sujet dit :
La situation, pour le code écrit ces jours-ci (C ++ 17 et suivant les directives officielles de base ) est la suivante:
"Oh ouais? Mais qu'en est-il de ...
... si j'écris simplement du code comme nous écrivions autrefois en C ++? "
En effet, vous pouvez simplement ignorer toutes les directives et écrire du code d'application qui fuit - et il se compilera et s'exécutera (et fuira), comme toujours.
Mais ce n'est pas une situation de «ne pas faire ça», où le développeur est censé être vertueux et exercer beaucoup de maîtrise de soi; il n'est tout simplement pas plus simple d'écrire du code non conforme, ni plus rapide à écrire, ni plus performant. Peu à peu, il deviendra également plus difficile à écrire, car vous feriez face à un "décalage d'impédance" croissant avec ce que le code conforme fournit et attend.
... si je
reintrepret_cast
? Ou faire de l'arithmétique pointeur complexe? Ou d'autres piratages? "En effet, si vous y pensez, vous pouvez écrire du code qui gâche les choses malgré un bon comportement avec les directives. Mais:
... le développement de la bibliothèque? "
Si vous êtes un développeur de bibliothèque C ++, vous écrivez du code dangereux impliquant des pointeurs bruts, et vous devez coder avec soin et responsabilité - mais ce sont des morceaux de code autonomes écrits par des experts (et plus important encore, examinés par des experts).
Donc, c'est comme Bjarne l'a dit: Il n'y a vraiment aucune motivation à collecter les déchets en général, comme vous tous, mais assurez-vous de ne pas produire de déchets. GC devient un non-problème avec C ++.
Cela ne veut pas dire que le GC n'est pas un problème intéressant pour certaines applications spécifiques, lorsque vous souhaitez utiliser des stratégies d'allocation et de désallocation personnalisées. Pour ceux que vous voudriez une allocation et une désallocation personnalisées, pas un GC au niveau de la langue.
la source
L'idée derrière C ++ était que vous ne paieriez aucun impact sur les performances des fonctionnalités que vous n'utilisez pas. Ainsi, l'ajout de garbage collection aurait signifié que certains programmes s'exécutent directement sur le matériel comme le fait C et d'autres au sein d'une sorte de machine virtuelle d'exécution.
Rien ne vous empêche d'utiliser une certaine forme de pointeurs intelligents liés à un mécanisme tiers de récupération de place. Il me semble me rappeler que Microsoft a fait quelque chose comme ça avec COM et cela ne s'est pas bien passé.
la source
Pour répondre à la plupart des questions «pourquoi» sur C ++, lisez Conception et évolution de C ++
la source
L'un des principes fondamentaux du langage C d'origine est que la mémoire est composée d'une séquence d'octets, et que le code n'a qu'à se soucier de ce que signifient ces octets au moment exact où ils sont utilisés. Le C moderne permet aux compilateurs d'imposer des restrictions supplémentaires, mais C inclut - et C ++ conserve - la possibilité de décomposer un pointeur en une séquence d'octets, d'assembler toute séquence d'octets contenant les mêmes valeurs dans un pointeur, puis d'utiliser ce pointeur pour accéder à l'objet précédent.
Bien que cette capacité puisse être utile - voire indispensable - dans certains types d'applications, un langage qui inclut cette capacité sera très limité dans sa capacité à prendre en charge tout type de collecte de déchets utile et fiable. Si un compilateur ne sait pas tout ce qui a été fait avec les bits qui composent un pointeur, il n'aura aucun moyen de savoir si des informations suffisantes pour reconstruire le pointeur peuvent exister quelque part dans l'univers. Étant donné qu'il serait possible que ces informations soient stockées de manière à ce que l'ordinateur ne puisse pas y accéder même s'il les connaissait (par exemple, les octets constituant le pointeur auraient pu être affichés à l'écran suffisamment longtemps pour que quelqu'un puisse écrire) vers le bas sur un morceau de papier), il peut être littéralement impossible pour un ordinateur de savoir si un pointeur pourrait éventuellement être utilisé à l'avenir.
Une particularité intéressante de nombreux cadres récupérés par les déchets est qu'une référence d'objet n'est pas définie par les modèles de bits qui y sont contenus, mais par la relation entre les bits contenus dans la référence d'objet et d'autres informations détenues ailleurs. En C et C ++, si le modèle de bits stocké dans un pointeur identifie un objet, ce modèle de bits identifiera cet objet jusqu'à ce que l'objet soit explicitement détruit. Dans un système GC typique, un objet peut être représenté par un modèle de bits 0x1234ABCD à un moment donné, mais le cycle GC suivant peut remplacer toutes les références à 0x1234ABCD par des références à 0x4321BABE, après quoi l'objet serait représenté par ce dernier modèle. Même si l'on devait afficher le modèle de bits associé à une référence d'objet, puis le relire plus tard à partir du clavier,
la source
Toutes les discussions techniques compliquent trop le concept.
Si vous mettez automatiquement GC en C ++ pour toute la mémoire, envisagez quelque chose comme un navigateur Web. Le navigateur Web doit charger un document Web complet ET exécuter des scripts Web. Vous pouvez stocker des variables de script Web dans l'arborescence de documents. Dans un GRAND document dans un navigateur avec de nombreux onglets ouverts, cela signifie que chaque fois que le GC doit effectuer une collecte complète, il doit également numériser tous les éléments du document.
Sur la plupart des ordinateurs, cela signifie que des DÉFAUTS DE PAGE se produiront. Donc, la raison principale, pour répondre à la question est que des DÉFAUTS DE PAGE se produiront. Vous le saurez comme lorsque votre PC commence à faire beaucoup d'accès au disque. C'est parce que le GC doit toucher beaucoup de mémoire afin de prouver les pointeurs invalides. Lorsque vous avez une application de bonne foi utilisant beaucoup de mémoire, devoir analyser tous les objets chaque collection est un ravage en raison des défauts de page. Une erreur de page survient lorsque la mémoire virtuelle doit être relue dans la RAM à partir du disque.
La bonne solution consiste donc à diviser une application en parties qui ont besoin de GC et celles qui n'en ont pas besoin. Dans le cas de l'exemple de navigateur Web ci-dessus, si l'arborescence de documents a été allouée avec malloc, mais que le javascript a fonctionné avec GC, chaque fois que le GC démarre, il ne scanne qu'une petite partie de la mémoire et tous les éléments PAGED OUT de la mémoire pour l'arborescence des documents n'a pas besoin d'être paginée.
Pour mieux comprendre ce problème, recherchez la mémoire virtuelle et la façon dont elle est implémentée dans les ordinateurs. Il s'agit du fait que 2 Go sont disponibles pour le programme quand il n'y a pas vraiment beaucoup de RAM. Sur les ordinateurs modernes avec 2 Go de RAM pour un système 32BIt, ce n'est pas un problème à condition qu'un seul programme soit en cours d'exécution.
Comme exemple supplémentaire, considérons une collection complète qui doit tracer tous les objets. Vous devez d'abord analyser tous les objets accessibles via les racines. Analysez ensuite tous les objets visibles à l'étape 1. Analysez ensuite les destructeurs en attente. Revenez ensuite à toutes les pages et désactivez tous les objets invisibles. Cela signifie que de nombreuses pages peuvent être échangées à plusieurs reprises.
Donc, ma réponse pour faire court est que le nombre de DÉFAUTS DE PAGE qui se produisent à la suite de toucher toute la mémoire rend impossible le GC complet pour tous les objets dans un programme et donc le programmeur doit voir GC comme une aide pour des choses comme les scripts et le travail de base de données, mais faites des choses normales avec la gestion manuelle de la mémoire.
Et l'autre raison très importante est bien sûr les variables globales. Pour que le collecteur sache qu'un pointeur de variable globale se trouve dans le GC, il faudrait des mots-clés spécifiques, et donc le code C ++ existant ne fonctionnerait pas.
la source
RÉPONSE COURTE: Nous ne savons pas comment effectuer la collecte des ordures de manière efficace (avec un temps et un espace supplémentaires mineurs) et correctement tout le temps (dans tous les cas possibles).
LONG RÉPONSE: Tout comme C, C ++ est un langage système; cela signifie qu'il est utilisé lorsque vous écrivez du code système, par exemple un système d'exploitation. En d'autres termes, C ++ est conçu, tout comme C, avec les meilleures performances possibles comme cible principale. Le standard du langage n'ajoutera aucune fonctionnalité susceptible d'entraver l'objectif de performance.
Cela met en pause la question: pourquoi la collecte des ordures entrave les performances? La principale raison est que, en ce qui concerne la mise en œuvre, nous [les informaticiens] ne savons pas comment faire la collecte des ordures avec un minimum de frais généraux, dans tous les cas. Par conséquent, il est impossible pour le compilateur C ++ et le système d'exécution d'effectuer une collecte de déchets efficace tout le temps. D'un autre côté, un programmeur C ++ devrait connaître sa conception / implémentation et il est la meilleure personne pour décider de la meilleure façon de faire la collecte des ordures.
Enfin, si le contrôle (matériel, détails, etc.) et les performances (temps, espace, puissance, etc.) ne sont pas les principales contraintes, alors C ++ n'est pas l'outil d'écriture. D'autres langages pourraient mieux servir et offrir une gestion d'exécution [cachée] plus importante, avec les frais généraux nécessaires.
la source
Lorsque nous comparons C ++ avec Java, nous voyons que C ++ n'a pas été conçu avec le Garbage Collection implicite à l'esprit, alors que Java l'était.
Avoir des choses comme des pointeurs arbitraires dans C-Style est non seulement mauvais pour les implémentations GC, mais cela détruirait également la compatibilité descendante pour une grande quantité de C ++ - code hérité.
En plus de cela, C ++ est un langage qui est destiné à s'exécuter en tant qu'exécutable autonome au lieu d'avoir un environnement d'exécution complexe.
Dans l'ensemble: oui, il pourrait être possible d'ajouter Garbage Collection à C ++, mais dans un souci de continuité, il est préférable de ne pas le faire.
la source
Principalement pour deux raisons:
C ++ propose déjà la gestion manuelle de la mémoire, l'allocation de pile, RAII, les conteneurs, les pointeurs automatiques, les pointeurs intelligents ... Cela devrait suffire. Les récupérateurs sont destinés aux programmeurs paresseux qui ne veulent pas passer 5 minutes à réfléchir à qui devrait posséder quels objets ou quand les ressources devraient-elles être libérées. Ce n'est pas ainsi que nous faisons les choses en C ++.
la source
Imposer la collecte des ordures est vraiment un changement de paradigme de bas en haut niveau.
Si vous regardez la façon dont les chaînes sont gérées dans un langage avec garbage collection, vous constaterez qu'elles autorisent UNIQUEMENT des fonctions de manipulation de chaînes de haut niveau et n'autorisent pas l'accès binaire aux chaînes. Autrement dit, toutes les fonctions de chaîne vérifient d'abord les pointeurs pour voir où se trouve la chaîne, même si vous ne dessinez qu'un octet. Donc, si vous effectuez une boucle qui traite chaque octet d'une chaîne dans une langue avec garbage collection, il doit calculer l'emplacement de base plus le décalage pour chaque itération, car il ne peut pas savoir quand la chaîne a été déplacée. Ensuite, vous devez penser aux tas, piles, fils, etc.
la source