16 votes

Langages de programmation avec ou sans collecte d'informations (garbage collection)

Donc, si je comprends bien, le ramasseur d'ordures désalloue automatiquement les objets qui ne sont plus utilisés par le programme, comme le ramasseur d'ordures de Java.

J'ai entendu dire que dans des langages comme le C qui ne prennent pas en charge le ramassage des déchets, les programmes peuvent avoir des fuites de mémoire et par la suite épuiser la mémoire.

Quelles sont donc les erreurs commises par les programmeurs dans des langages comme le C qui ne prennent pas en charge le ramassage des déchets ? Je pense qu'ils ne désallouent pas les objets lorsqu'ils ne sont plus utilisés. Mais est-ce que ce sont les seules erreurs que l'on peut faire à cause de l'absence de ramasse-miettes ?

19voto

Lee B Points 1748
  • Délocaliser les choses dont vous avez besoin

  • Ne pas désallouer les choses dont vous n'avez plus besoin (parce que vous ne suivez pas bien les allocations/utilisation/frees).

  • Réaffectation de nouvelles instances de choses qui existent déjà (un effet secondaire d'un mauvais suivi).

  • Désallouer quelque chose que vous avez déjà libéré

  • Désallouer quelque chose qui n'existe pas (un pointeur nul)

Il y en a probablement plus. Le fait est que la gestion de la mémoire est délicate et qu'il est préférable d'utiliser une sorte de mécanisme de suivi et d'abstraction d'allocation/libération. En tant que tel, il est préférable de l'intégrer dans votre langage, afin qu'il puisse vous faciliter la tâche. La gestion manuelle de la mémoire n'est pas la fin du monde - c'est certainement faisable - mais de nos jours, à moins que vous n'écriviez du code en temps réel, des pilotes matériels ou (peut-être, peut-être) le code central ultra-optimisé du dernier jeu, l'effort manuel ne vaut pas la peine, sauf comme exercice académique.

13voto

Steve314 Points 12599

IMO, les langages à ramassage d'ordures ont des problèmes complémentaires à ceux des langages sans ramassage d'ordures. Pour chaque problème, il existe un bogue non caractéristique de GC et un bogue caractéristique de GC - une responsabilité du programmeur non GC et une responsabilité du programmeur GC.

Les programmeurs GC peuvent croire qu'ils sont déchargés de la responsabilité de libérer les objets, mais les objets contiennent des ressources autres que la mémoire - des ressources qui doivent souvent être libérées en temps opportun afin qu'elles puissent être acquises ailleurs - par exemple, des poignées de fichiers, des verrous d'enregistrement, des mutex...

Là où un programmeur non GC aurait une référence pendante (et très souvent une référence qui n'est pas un bogue, puisqu'un drapeau ou un autre état la marquerait comme ne devant pas être utilisée), un programmeur GC a une fuite de mémoire. Ainsi, là où le programmeur non GC doit s'assurer que free/delete est appelé de manière appropriée, le programmeur GC doit s'assurer que les références indésirables sont annulées ou éliminées de manière appropriée.

Il est dit ici que les pointeurs intelligents ne traitent pas les cycles d'élimination des déchets. Ce n'est pas forcément vrai - il existe des schémas de comptage de références qui peuvent briser les cycles et qui garantissent également l'élimination opportune de la mémoire résiduelle, et au moins une implémentation Java a utilisé (et peut encore le faire) un schéma de comptage de références qui pourrait tout aussi bien être implémenté comme un schéma de pointeur intelligent en C++.

Collecte simultanée de cycles dans les systèmes à comptage de référence

Bien sûr, cela ne se fait pas normalement - en partie parce que vous pouvez tout aussi bien utiliser un langage GC, mais aussi en partie parce que cela briserait des conventions clés du C++. Vous voyez, une grande partie du code C++ - y compris la bibliothèque standard - s'appuie fortement sur la convention RAII (Resource Allocation Is Initialisation), et cela repose sur des appels de destructeurs fiables et opportuns. Dans tout GC qui gère les cycles, cela est tout simplement impossible. Lors de la rupture d'un cycle d'ordures, vous ne pouvez pas savoir quel destructeur appeler en premier sans aucun problème de dépendance - ce n'est peut-être même pas possible, car il peut y avoir plus de dépendances cycliques que de simples références mémoire. La solution - en Java etc, il n'y a aucune garantie que les finaliseurs seront appelés. La collecte d'ordures ne collecte qu'un type très spécifique d'ordures - la mémoire. Toutes les autres ressources doivent être nettoyées manuellement, comme elles l'auraient été en Pascal ou en C, et sans l'avantage de destructeurs fiables de type C++.

Résultat final : une grande partie du nettoyage qui est "automatisé" en C++ doit être effectué manuellement en Java, C#, etc. Bien sûr, "automatisé" a besoin de guillemets parce que le programmeur est responsable de s'assurer que delete est appelé correctement pour tous les objets alloués au tas - mais dans les langages GC, il y a des responsabilités différentes mais complémentaires du programmeur. D'une manière ou d'une autre, si le programmeur ne parvient pas à gérer correctement ces responsabilités, vous obtenez des bogues.

[ EDIT - il y a des cas où Java, C# etc. font évidemment un nettoyage fiable (mais pas nécessairement opportun), et les fichiers en sont un exemple. Il s'agit d'objets pour lesquels les cycles de référence ne peuvent pas se produire - soit parce que (1) ils ne contiennent pas de références du tout, (2) il existe une preuve statique que les références qu'ils contiennent ne peuvent pas directement ou indirectement mener à un autre objet du même type, ou (3) la logique d'exécution garantit que les cycles ne sont pas possibles, même si les chaînes/arbres/autres sont possibles. Les cas (1) et (2) sont extrêmement courants pour les objets de gestion de ressources par opposition aux nœuds de structure de données - peut-être universel. Le compilateur lui-même ne peut pas raisonnablement garantir (3), cependant. Ainsi, alors que les développeurs de la bibliothèque standard, qui écrivent les classes de ressources les plus importantes, peuvent garantir un nettoyage fiable pour celles-ci, la règle générale est toujours que le nettoyage fiable des ressources non-mémoire ne peut être garanti pour un GC, et cela pourrait affecter les ressources définies par l'application].

Franchement, passer d'un statut de non-CG à celui de CG (ou vice-versa) n'est pas une baguette magique. Cela peut faire disparaître les problèmes suspects habituels, mais cela signifie simplement que vous avez besoin de nouvelles compétences pour prévenir (et déboguer) un tout nouvel ensemble de suspects.

Un bon programmeur devrait dépasser le stade du "qui est de quel côté ?" et apprendre à gérer les deux.

7voto

Noon Silk Points 30396

Eh bien, les erreurs que vous pouvez faire sont :

  • Ne pas désallouer les choses dont on n'a pas besoin
  • Désallouer les choses dont vous avez besoin

Il y a d'autres erreurs que tu peux faire, mais celles-là sont celles qui concernent spécifiquement à la collecte des déchets.

3voto

Alex Gaynor Points 6217

En plus de ce que dit Silky, vous pouvez aussi doublement désallouer quelque chose.

2voto

Andrew Keeton Points 6268

En C, vous devez appeler manuellement free sur la mémoire allouée avec malloc . Bien que cela ne semble pas si mal, cela peut devenir très désordonné lorsqu'il s'agit de structures de données distinctes (comme des listes chaînées) qui pointent vers les mêmes données. Vous pourriez finir par accéder à la mémoire libérée ou à la mémoire doublement libérée, ce qui entraîne des erreurs et peut introduire des failles de sécurité.

De plus, en C++, il faut faire attention à ne pas mélanger les éléments suivants new[]/delete y new/delete[] .

Par exemple, la gestion de la mémoire est quelque chose qui nécessite que le programmeur sache exactement pourquoi

const char *getstr() { return "Hello, world!" }

est très bien mais

const char *getstr() {
    char x[BUF_SIZE];
    fgets(x, BUF_SIZE, stdin);
    return x;
}

est une très mauvaise chose.

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