Eh bien, je sais qu'il existe des choses comme malloc / free for C, et new / using-a-destructor pour la gestion de la mémoire en C ++, mais je me demandais pourquoi il n'y a pas de "nouvelles mises à jour" dans ces langages qui permettent à l'utilisateur de avoir la possibilité de gérer manuellement la mémoire, ou que le système le fasse automatiquement (nettoyage de la mémoire)?
Une question plutôt nouvelle, mais qui ne figure dans CS que depuis environ un an.
garbage-collection
Dark Templar
la source
la source
Réponses:
Le ramassage des ordures nécessite des structures de données pour suivre les allocations et / ou le comptage des références. Celles-ci créent une surcharge en mémoire, en performances et en complexité du langage. C ++ est conçu pour être "proche du métal", autrement dit, il prend le côté plus performant des fonctionnalités de compromis par rapport à la commodité. D'autres langues font ce compromis différemment. C’est l’une des considérations à prendre en compte lors du choix d’une langue, l’emphase que vous préférez.
Cela dit, de nombreux schémas de comptage de références en C ++ sont assez légers et performants, mais ils se trouvent dans des bibliothèques, à la fois commerciales et à code source ouvert, plutôt qu’une partie du langage lui-même. Compter les références pour gérer la durée de vie des objets n’est pas la même chose que le garbage collection, mais il résout bon nombre des mêmes problèmes et s’adapte mieux à l’approche de base de C ++.
la source
À proprement parler, il n’existe aucune gestion de la mémoire en langage C. malloc () et free () ne sont pas des mots-clés du langage, mais simplement des fonctions appelées à partir d'une bibliothèque. Cette distinction est peut-être pédante à présent, car malloc () et free () font partie de la bibliothèque standard C et seront fournies par toute implémentation conforme de C au standard, mais ce n’était pas toujours le cas par le passé.
Pourquoi voudriez-vous un langage sans standard pour la gestion de la mémoire? Cela remonte aux origines de C en tant qu '"assemblage portable". Il existe de nombreux cas de matériel et d'algorithmes pouvant tirer parti, voire nécessitant, des techniques de gestion de la mémoire spécialisées. À ma connaissance, il n’existe aucun moyen de désactiver complètement la gestion de la mémoire native de Java et de la remplacer par la vôtre. Ce n'est tout simplement pas acceptable dans certaines situations de ressources élevées / hautes performances. C offre une flexibilité presque complète pour choisir exactement l'infrastructure que votre programme utilisera. Le prix à payer est que le langage C fournit très peu d'aide pour écrire un code correct, sans bug.
la source
malloc()
oufree()
. (par exemple, des compilateurs MLAP pour PIC)La vraie réponse est que le seul moyen de créer un mécanisme de collecte des ordures sûr et efficace consiste à prendre en charge les références opaques au niveau de la langue . (Ou, inversement, un manque de prise en charge au niveau de la langue pour la manipulation directe de la mémoire.)
Java et C # peuvent le faire car ils ont des types de référence spéciaux qui ne peuvent pas être manipulés. Cela donne au moteur d'exécution la liberté de déplacer des objets alloués en mémoire , ce qui est essentiel pour une implémentation GC haute performance.
Pour mémoire, aucune implémentation moderne du GC n’utilise le comptage de références , ce qui en fait un véritable casse-tête. Les GC modernes utilisent la collection générationnelle, où les nouvelles allocations sont traitées essentiellement de la même manière que les allocations de pile dans un langage tel que C ++, puis tous les objets nouvellement alloués encore en vie sont déplacés vers un espace "survivant" séparé et une génération entière. des objets est désalloué à la fois.
Cette approche a des avantages et des inconvénients: l'avantage réside dans le fait que les allocations de segment de mémoire dans un langage prenant en charge le GC sont aussi rapides que les allocations de pile dans un langage ne prenant pas en charge le GC, et l'inconvénient est que les objets devant être nettoyés avant d'être détruits besoin d' un mécanisme distinct (par exemple C de #
using
mot - clé) ou bien leur code de nettoyage fonctionne non déterministe.Notez que l'une des clés d'un CPG hautes performances est la prise en charge linguistique d'une classe de références spécifique. C n'a pas cette langue et ne le fera jamais; Comme C ++ a une surcharge d'opérateur, il pourrait émuler un type de pointeur GC, bien que cela devrait être fait avec précaution. En fait, lorsque Microsoft a inventé son dialecte C ++ qui s'exécutait sous le CLR (le runtime .NET), il a fallu inventer une nouvelle syntaxe pour "références de style C #" (par exemple
Foo^
) afin de les distinguer des "références de style C ++". (par exempleFoo&
).Ce que C ++ a, et que les programmeurs C ++ utilisent régulièrement , ce sont des pointeurs intelligents , qui ne sont en réalité qu'un mécanisme de comptage de références. Je ne considérerais pas le comptage de références comme un "vrai" GC, mais il offre bon nombre des mêmes avantages, au détriment des performances plus lentes que la gestion manuelle de la mémoire ou le véritable GC, mais avec l’avantage de la destruction déterministe.
À la fin de la journée, la réponse se résume vraiment à une fonctionnalité de conception de langage. C a fait un choix, C ++ a fait un choix qui lui a permis d’être rétro-compatible avec le C tout en offrant des alternatives assez bonnes pour la plupart des applications, et Java et C # ont fait un choix différent, incompatible avec le C, mais également suffisant pour la plupart des fins. Malheureusement, il n’ya pas de solution miracle, mais connaître les différents choix qui s’offrent à vous vous aidera à choisir celui qui convient le mieux au programme que vous essayez de créer.
la source
std::unique_ptr
s'agit d'un "support de niveau de langue pour les références opaques"? (Ce n'était pas le type d'assistance que je voulais dire et je ne pense pas non plus que cela soit suffisant si la prise en charge de la manipulation directe de mémoire n'était pas supprimée du C ++.) Je mentionne les pointeurs intelligents dans ma réponse et je considéreraisstd:unique_ptr
un pointeur intelligent , puisqu'il effectue effectivement le comptage de références, il ne prend en charge que les cas particuliers où le nombre de références est égal à zéro ou à un (etstd::move
constitue le mécanisme de mise à jour du décompte de références).std::unique_ptr
n'a pas de compte de références etstd::move
n'a rien à voir avec les références (donc "non" touché de performance). Je vois cependant votre argument, destd::shared_ptr
même que le décompte de références implicite mis à jour parstd::move
:)malloc
etfree
. Alors oui, un GC peut être considérablement plus rapide. (Notez que j'ai dit "peut être" - bien sûr, de nombreux facteurs affectent les performances exactes de chaque programme.)Parce que, lorsque vous utilisez la puissance de C ++, il n’est pas nécessaire.
Herb Sutter: " Je n'ai pas écrit delete depuis des années. "
voir Écrire du code C ++ moderne: comment le C ++ a évolué au fil des ans 21:10
Cela peut surprendre de nombreux programmeurs C ++ expérimentés.
la source
"Tout", un ramasse-miettes est un processus qui s'exécute périodiquement pour vérifier s'il y a des objets non référencés en mémoire et s'il y a des suppressions. (Oui, je sais que c'est une simplification excessive). Ce n'est pas une propriété du langage, mais le cadre.
Il y a des éboueurs écrits pour C et C ++ - celui-ci par exemple.
Une des raisons pour lesquelles on n'a pas "ajouté" à la langue pourrait être due au volume même de code existant qui ne l'utilisera jamais car ils utilisent leur propre code pour gérer la mémoire. Une autre raison peut être que les types d'applications écrites en C et C ++ n'ont pas besoin de la surcharge associée à un processus de récupération de place.
la source
malloc
etfree
, vous interrompez mon programme correct.free
avant d'avoir fini. Mais votre ramasse-miettes proposé qui ne libère pas la mémoire tant que je n'aifree
pas appelé explicitement n'est pas du tout un ramasse-miettes.C a été conçu à une époque où la collecte des ordures ménagères était à peine une option. Il était également destiné aux utilisations pour lesquelles la récupération de place ne fonctionnerait généralement pas - environnements sans système d'exploitation, environnements en temps réel avec une mémoire minimale et une prise en charge minimale de l'exécution. Rappelez-vous que C était le langage d'implémentation du premier Unix, qui s'exécutait sur un pdp-11 avec 64 * K * octets de mémoire. Le C ++ était à l'origine une extension du C - le choix avait déjà été fait et il est très difficile de greffer la récupération de place sur un langage existant. C'est le genre de chose qui doit être construit à partir du rez-de-chaussée.
la source
Je n'ai pas les citations exactes mais Bjarne et Herb Sutter disent quelque chose dans le sens suivant:
Dans le C ++ moderne, vous utilisez des pointeurs intelligents et vous ne perdez donc pas de temps.
la source
Vous demandez pourquoi ces langues n'ont pas été mises à jour pour inclure un récupérateur de place facultatif.
Le problème avec la récupération de place facultative est qu'il est impossible de mélanger du code utilisant les différents modèles. En d’autres termes, si j’écris du code qui suppose que vous utilisez un ramasse-miettes, vous ne pouvez pas l’utiliser dans votre programme pour lequel le ramasse-miettes est désactivé. Si vous le faites, ça va fuir partout.
la source
Pouvez-vous imaginer écrire un gestionnaire de périphérique dans une langue avec la récupération de place? Combien de bits peuvent arriver sur la ligne pendant le fonctionnement du GC?
Ou un système d'exploitation? Comment pouvez-vous démarrer la récupération de place en cours d'exécution avant même de démarrer le noyau?
C est conçu pour un niveau bas proche des tâches matérielles. Le problème? est-ce une langue si agréable que c'est un bon choix pour de nombreuses tâches de niveau supérieur. Les responsables des langues sont conscients de ces utilisations, mais ils doivent en priorité prendre en charge les exigences des pilotes de périphérique, du code intégré et des systèmes d'exploitation.
la source
La réponse brève et ennuyeuse à cette question est qu'il doit exister un langage non récupéré pour les personnes qui écrivent les éboueurs. Il n’est pas facile d’un point de vue conceptuel d’avoir un langage qui permette en même temps un contrôle très précis de la structure de la mémoire et sur lequel se trouve un CPG.
L'autre question est de savoir pourquoi C et C ++ n'ont pas de récupérateur de place. Eh bien, je sais que le C ++ en a quelques-uns, mais ils ne sont pas très populaires car ils sont obligés de traiter avec un langage qui n'a pas été conçu pour être GC-ed, et les personnes qui l'utilisent encore cet âge n'est pas vraiment le genre qui manque un GC.
De plus, au lieu d’ajouter GC à un ancien langage non GC-ed, il est en fait plus facile de créer un nouveau langage qui utilise la même syntaxe tout en prenant en charge un GC. Java et C # en sont de bons exemples.
la source
Il y a divers problèmes, y compris ...
delete
oufree
explicite. L’approche GC présente toujours un avantage - aucune référence en suspens - et l’analyse statique peut identifier certains cas, mais là encore, il n’existe pas de solution parfaite pour tous les cas.Fondamentalement, cela concerne en partie l'âge des langues, mais il y aura toujours une place pour les langues autres que le GC, même si c'est un peu un créneau. Et sérieusement, en C ++, le manque de GC n'est pas un problème: votre mémoire est gérée différemment, mais elle n'est pas non gérée.
C ++ géré par Microsofts a au moins une certaine capacité à mélanger GC et non GC dans la même application, ce qui permet de combiner les avantages de chacun, mais je n'ai pas l'expérience nécessaire pour dire si cela fonctionne bien dans la pratique.
Rep-whoring liens vers des réponses de la mienne ...
la source
Le ramassage des ordures est fondamentalement incompatible avec un langage système utilisé pour développer des pilotes pour du matériel compatible DMA.
Il est tout à fait possible que le seul pointeur sur un objet soit stocké dans un registre matériel de certains périphériques. Puisque le ramasse-miettes ne le saurait pas, il penserait que l'objet est inaccessible et le récupérera.
Cet argument est double pour le compactage de GC. Même si vous aviez pris soin de conserver les références en mémoire aux objets utilisés par les périphériques matériels, lorsque le CPG avait déplacé l'objet, il ne savait pas comment mettre à jour le pointeur contenu dans le registre de configuration des périphériques.
Vous avez donc besoin d'un mélange de tampons DMA immobiles et d'objets gérés par GC, ce qui signifie que vous avez tous les inconvénients des deux.
la source
Parce que C & C ++ sont des langages de niveau relativement bas destinés à un usage général, même pour, par exemple, fonctionner sur un processeur 16 bits avec 1 Mo de mémoire dans un système embarqué, qui ne pouvait se permettre de gaspiller de la mémoire avec gc.
la source
Il existe des garbage collectors en C ++ et C. Vous ne savez pas comment cela fonctionne en C, mais en C ++, vous pouvez utiliser RTTI pour détecter dynamiquement votre graphe d'objets et l'utiliser pour le garbage collection.
À ma connaissance, vous ne pouvez pas écrire en Java sans un ramasse-miettes. Une petite recherche a révélé ceci .
La principale différence entre Java et C / C ++ est qu’en C / C ++, le choix vous appartient toujours, alors qu’en Java, les options sont souvent laissées de côté.
la source
C'est un compromis entre performance et sécurité.
Il n’existe aucune garantie que vos déchets soient collectés en Java; ils risquent donc de perdre du temps à utiliser de l’espace, tandis que l’analyse des objets non référencés (par exemple, des déchets) prend plus de temps que la suppression ou la libération explicite d’un objet inutilisé.
Bien entendu, l’avantage est que l’on peut construire un langage sans pointeurs ni fuites de mémoire, ce qui permet de produire un code correct.
Il peut y avoir parfois un léger avantage «religieux» dans ces débats - soyez prévenus!
la source
Voici une liste de problèmes inhérents au GC, qui le rendent inutilisable dans un langage système tel que C:
Le CPG doit être inférieur au niveau du code dont il gère les objets. Il n'y a tout simplement pas un tel niveau dans un noyau.
Un GC doit arrêter le code géré de temps en temps. Maintenant, réfléchissez à ce qui se passerait si cela causait cela à votre noyau. Tous les traitements sur votre machine s’arrêteraient pendant une milliseconde, par exemple, pendant que le CPG analyse toutes les allocations de mémoire existantes. Cela tuerait toutes les tentatives visant à créer des systèmes fonctionnant dans des conditions strictes en temps réel.
Un GC doit pouvoir faire la distinction entre les pointeurs et les non-pointeurs. C'est-à-dire qu'il doit pouvoir examiner chaque objet de la mémoire existant et pouvoir produire une liste de décalages où ses pointeurs peuvent être trouvés.
Cette découverte doit être parfaite: le GC doit pouvoir chasser tous les indicateurs qu’il découvre. Si elle déréférencait un faux positif, elle risquerait de planter. Si elle ne parvenait pas à détecter un faux négatif, elle détruirait probablement un objet toujours en cours d'utilisation, en provoquant une panne du code géré ou une corruption silencieuse de ses données.
Cela nécessite absolument que les informations de type soient stockées dans chaque objet existant. Cependant, C et C ++ autorisent tous deux les anciens objets de données qui ne contiennent aucune information de type.
Le GC est une entreprise intrinsèquement lente. Les programmeurs qui ont été socialisés avec Java peuvent ne pas s'en rendre compte, mais les programmes peuvent être beaucoup plus rapides s'ils ne sont pas implémentés en Java. Et l'un des facteurs qui ralentissent Java est le GC. C'est ce qui empêche les langages GCed tels que Java d'être utilisés en superinformatique. Si votre machine coûte un million par an en consommation d'énergie, vous ne voulez pas payer même 10% de cela pour la collecte des ordures.
C et C ++ sont des langages créés pour prendre en charge tous les cas d'utilisation possibles. Et, comme vous le voyez, nombre de ces cas d'utilisation sont exclus du nettoyage de la mémoire. Ainsi, afin de prendre en charge ces cas d'utilisation, C / C ++ ne peut pas être nettoyé.
la source