Les memory leaks sont-elles correctes?

Est-il possible d’avoir une fuite de mémoire dans votre application C ou C ++?

Que faire si vous allouez de la mémoire et l’utilisez jusqu’à la toute dernière ligne de code de votre application (par exemple, le destructeur d’un object global)? Tant que la consommation de mémoire n’augmente pas avec le temps, est-il correct de faire confiance au système d’exploitation pour libérer votre mémoire lorsque votre application se termine (sous Windows, Mac et Linux)? Voulez-vous même considérer cela comme une véritable fuite de mémoire si la mémoire était utilisée de manière continue jusqu’à ce qu’elle soit libérée par le système d’exploitation.

Que se passe-t-il si une bibliothèque tierce a forcé cette situation sur vous? Refuserait d’utiliser cette bibliothèque tierce, quelle que soit sa qualité?

Je ne vois qu’un inconvénient pratique, à savoir que ces fuites bénignes apparaîtront avec les outils de détection des memory leaks en tant que faux positifs.

Non.

En tant que professionnels, la question que nous ne devrions pas nous poser est la suivante: “Est-ce que ça peut aller?” mais plutôt “Y a-t-il une bonne raison de le faire?” Et “chasser cette fuite de mémoire est une douleur” n’est pas une bonne raison.

J’aime garder les choses simples. Et la règle simple est que mon programme ne devrait avoir aucune fuite de mémoire.

Cela me simplifie la vie aussi. Si je détecte une fuite de mémoire, je l’élimine plutôt que de parcourir une structure d’arbre de décision complexe pour déterminer s’il s’agit d’une fuite de mémoire “acceptable”.

C’est similaire aux avertissements du compilateur – l’avertissement sera-t-il fatal à mon application particulière? Peut être pas.

Mais c’est en fin de compte une question de discipline professionnelle. Tolérer les avertissements du compilateur et tolérer les memory leaks est une mauvaise habitude qui va finalement me mordre à l’arrière.

Pour pousser les choses à l’extrême, serait-il acceptable pour un chirurgien de laisser une pièce d’équipement à l’intérieur d’un patient?

Bien qu’il soit possible qu’une circonstance survienne lorsque le coût / risque d’enlever cet équipement dépasse le coût / le risque de le laisser et qu’il peut y avoir des circonstances inoffensives, si j’ai vu cette question affichée sur SurgeonOverflow.com et voyait une réponse autre que “non”, cela compromettrait sérieusement ma confiance dans la profession médicale.

Si une bibliothèque tierce imposait cette situation, cela m’amènerait à soupçonner sérieusement la qualité globale de la bibliothèque en question. Ce serait comme si je testais une voiture et que je trouvais quelques rondelles et écrous en vrac dans l’un des porte-gobelets – ce n’est peut-être pas un problème en soi, mais cela montre un manque d’engagement envers la qualité.

Je ne considère pas que ce soit une fuite de mémoire à moins que la quantité de mémoire utilisée ne cesse de croître. Avoir de la mémoire inédite, même si elle n’est pas idéale, n’est pas un gros problème, à moins que la quantité de mémoire requirejse ne cesse d’augmenter.

Obtenons nos définitions correctement, d’abord. Une fuite de mémoire se produit lorsque la mémoire est allouée dynamicment, par exemple avec malloc() , et que toutes les références à la mémoire sont perdues sans la libre correspondante. Un moyen facile de faire un est comme ceci:

 #define BLK ((size_t)1024) while(1){ void * vp = malloc(BLK); } 

Notez qu’à chaque fois que la boucle while (1) est utilisée, 1024 octets (+ overhead) sont alloués et la nouvelle adresse est affectée à vp; il ne rest plus de pointeur sur les précédents blocs malloc. Ce programme est garanti pour s’exécuter jusqu’à ce que le tas s’épuise, et il n’y a aucun moyen de récupérer la mémoire malloc’ed. La mémoire “fuit” du tas, pour ne plus jamais être vue.

Ce que vous décrivez, cependant, ressemble à

 int main(){ void * vp = malloc(LOTS); // Go do something useful return 0; } 

Vous allouez la mémoire, travaillez-la jusqu’à la fin du programme. Ce n’est pas une fuite de mémoire; cela n’affecte pas le programme, et toute la mémoire sera récupérée automatiquement à la fin du programme.

En règle générale, vous devez éviter les memory leaks. Premièrement, parce que, comme l’altitude au-dessus de vous et le retour de carburant dans le hangar, la mémoire qui a fui et ne peut pas être récupérée est inutile; deuxièmement, il est beaucoup plus facile de coder correctement, pas de fuite de mémoire, au début que de trouver une fuite de mémoire plus tard.

En théorie non, dans la pratique, cela dépend .

Cela dépend vraiment de la quantité de données sur laquelle le programme fonctionne, de la fréquence d’exécution du programme et de son fonctionnement constant.

Si j’ai un programme rapide qui lit une petite quantité de données effectue un calcul et quitte, une petite fuite de mémoire ne sera jamais remarquée. Comme le programme ne fonctionne pas très longtemps et n’utilise qu’une petite quantité de mémoire, la fuite sera faible et libérée lorsque le programme existe.

D’un autre côté, si mon programme traite des millions d’enregistrements et fonctionne pendant une longue période, une petite fuite de mémoire peut provoquer un arrêt de la machine avec suffisamment de temps.

Comme pour les bibliothèques tierces qui ont des fuites, si elles posent problème, corrigez la bibliothèque ou trouvez une meilleure alternative. Si cela ne pose pas de problème, est-ce vraiment important?

Beaucoup de gens semblent avoir l’impression qu’une fois que vous libérez de la mémoire, elle retourne instantanément au système d’exploitation et peut être utilisée par d’autres programmes.

Ce n’est pas vrai Les systèmes d’exploitation gèrent généralement la mémoire dans les pages de 4 Ko. malloc et d’autres types de gestion de la mémoire obtiennent des pages du système d’exploitation et les sous-traitent comme bon leur semble. Il est fort probable que free() ne renverra pas de pages au système d’exploitation, en supposant que votre programme produira plus de mémoire ultérieurement.

Je ne dis pas que free() ne renvoie jamais de mémoire au système d’exploitation. Cela peut arriver, particulièrement si vous libérez de grandes quantités de mémoire. Mais il n’y a pas de garantie.

Le fait important: si vous ne libérez pas de la mémoire dont vous n’avez plus besoin, des mallocs supplémentaires consumnt encore plus de mémoire. Mais si vous libérez d’abord, malloc pourrait réutiliser la mémoire libérée à la place.

Qu’est-ce que cela signifie en pratique? Cela signifie que si vous savez que votre programme ne nécessitera plus de mémoire à partir de maintenant (par exemple, il est en phase de nettoyage), libérer de la mémoire n’est pas si important. Cependant, si le programme peut allouer plus de mémoire ultérieurement, vous devez éviter les memory leaks, en particulier celles qui peuvent se produire à plusieurs resockets.

Voir aussi ce commentaire pour plus de détails sur la raison pour laquelle libérer de la mémoire juste avant la fin est mauvaise.

Un commentateur n’a pas semblé comprendre que l’appel de free() n’autorise pas automatiquement les autres programmes à utiliser la mémoire libérée. Mais c’est tout l’intérêt de cette réponse!

Donc, pour convaincre les gens, je vais montrer un exemple où free () fait très bien. Pour faciliter le calcul, je vais prétendre que le système d’exploitation gère la mémoire en pages de 4 000 octets.

Supposons que vous allouiez dix mille blocs de 100 octets (pour plus de simplicité, j’ignore la mémoire supplémentaire nécessaire pour gérer ces allocations). Cela consum 1 Mo, soit 250 pages. Si vous libérez alors 9 000 de ces blocs au hasard, vous ne disposez que de 1 000 blocs, mais ils sont dispersés partout. Statistiquement, environ 5 pages seront vides. Les 245 autres auront chacun au moins un bloc alloué. Cela équivaut à 980 Ko de mémoire, ce qui ne peut pas être récupéré par le système d’exploitation – même si 100 Ko seulement sont alloués!

D’un autre côté, vous pouvez maintenant append 9 000 blocs supplémentaires à malloc sans augmenter la quantité de mémoire de votre programme.

Même si free() pouvait techniquement restituer de la mémoire au système d’exploitation, cela pourrait ne pas être le cas. free() doit atteindre un équilibre entre une exploitation rapide et une économie de mémoire. Et puis, un programme qui a déjà alloué beaucoup de mémoire puis libéré est susceptible de le faire à nouveau. Un serveur Web doit gérer les requêtes après demande – il est logique de garder de la mémoire disponible afin de ne pas avoir besoin de demander du temps au système d’exploitation.

Il n’y a rien de mal conceptuel à ce que le système d’exploitation soit nettoyé après l’exécution de l’application.

Cela dépend vraiment de l’application et de la façon dont elle sera exécutée. Les fuites permanentes dans une application qui doit fonctionner pendant des semaines doivent être sockets en compte, mais un petit outil qui calcule un résultat sans avoir besoin de trop de mémoire ne devrait pas être un problème.

Il y a une raison pour laquelle de nombreux langages de script ne collectent pas de références cycliques… pour leurs modèles d’utilisation, ce n’est pas un problème réel et serait donc un gaspillage de ressources autant que la mémoire gaspillée.

Je pense que la réponse est non, ne permettez jamais une fuite de mémoire, et j’ai quelques raisons que je n’ai pas vues explicitement. Il y a de très bonnes réponses techniques ici, mais je pense que la vraie réponse dépend de raisons plus sociales / humaines.

(Tout d’abord, notez que, comme d’autres l’ont mentionné, une vraie fuite se produit lorsque votre programme perd à tout moment la trace des ressources mémoire allouées. En C, cela se produit lorsque vous malloc() un pointeur sans faire un free() premier.)

Le point essentiel de votre décision ici est l’habitude. Lorsque vous codez dans une langue qui utilise des pointeurs, vous allez utiliser beaucoup de pointeurs. Et les pointeurs sont dangereux; Ils constituent le moyen le plus simple d’append toutes sortes de problèmes graves à votre code.

Lorsque vous codez, parfois vous allez être sur la balle et parfois vous allez être fatigué ou furieux ou inquiet. Pendant ces périodes un peu distraites, vous codez plus sur le pilote automatique. L’effet de pilote automatique ne fait pas la différence entre un code unique et un module dans un projet plus important. Pendant ces moments, les habitudes que vous établissez vont se retrouver dans votre base de code.

Donc non, ne permettez jamais les memory leaks pour la même raison que vous devriez toujours vérifier vos angles morts lorsque vous changez de voie, même si vous êtes la seule voiture sur la route pour le moment. Pendant les périodes où votre cerveau actif est distrait, de bonnes habitudes sont tout ce qui peut vous sauver des erreurs désastreuses.

Au-delà du problème de l’habitude, les pointeurs sont complexes et requièrent souvent beaucoup de puissance cérébrale pour suivre mentalement. Il est préférable de ne pas “embrouiller l’eau” en ce qui concerne votre utilisation des pointeurs, surtout lorsque vous êtes novice en programmation.

Il y a aussi un aspect plus social. En utilisant correctement malloc() et free() , quiconque regarde votre code sera à l’aise; vous gérez vos ressources. Si vous ne le faites pas, cependant, ils suspecteront immédiatement un problème.

Peut-être vous êtes-vous rendu compte que la fuite de mémoire ne fait de mal à rien dans ce contexte, mais chaque responsable de votre code devra le faire aussi quand il lit ce morceau de code. En utilisant free() vous supprimez la nécessité de prendre en compte le problème.

Enfin, la programmation consiste à écrire un modèle mental d’un processus dans un langage non ambigu, afin qu’une personne et un ordinateur puissent parfaitement comprendre ledit processus. Une partie essentielle de la bonne pratique de programmation ne consiste jamais à introduire une ambiguïté inutile.

La programmation intelligente est flexible et générique. Une mauvaise programmation est ambiguë.

Je pense que dans votre situation, la réponse est peut-être que ça va. Mais vous devez absolument documenter que la fuite de mémoire est une décision consciente. Vous ne voulez pas qu’un programmeur de maintenance intervienne, claque votre code dans une fonction et l’appelle un million de fois. Donc, si vous décidez qu’une fuite est acceptable, vous devez la documenter (IN BIG LETTERS) pour quiconque devra éventuellement travailler sur le programme.

S’il s’agit d’une bibliothèque tierce, vous pouvez être coincé. Mais documenter définitivement que cette fuite se produit.

Mais fondamentalement, si la fuite de mémoire est une quantité connue comme un tampon de 512 Ko ou quelque chose, alors c’est un non-problème. Si la fuite de mémoire ne cesse de croître, comme chaque fois que vous appelez une bibliothèque, votre mémoire augmente de 512 Ko et n’est pas libérée, alors vous pouvez avoir un problème. Si vous le documentez et contrôlez le nombre de fois que l’appel est exécuté, il peut être gérable. Mais alors vous avez vraiment besoin de documentation parce que 512, ce n’est pas beaucoup, 512 plus d’un million d’appels, c’est beaucoup.

Vous devez également vérifier la documentation de votre système d’exploitation. S’il s’agissait d’un périphérique intégré, il se peut que certains systèmes d’exploitation ne libèrent pas toute la mémoire d’un programme qui existe. Je ne suis pas sûr, peut-être que ce n’est pas vrai. Mais ça vaut la peine de regarder.

Je vais vous donner la réponse impopulaire mais pratique selon laquelle il est toujours erroné de libérer de la mémoire, à moins que cela ne réduise l’utilisation de la mémoire de votre programme . Par exemple, un programme qui effectue une allocation unique ou une série d’allocations pour charger le jeu de données qu’il utilisera pendant toute sa durée de vie n’a pas besoin de libérer quoi que ce soit. Dans le cas plus commun d’un programme volumineux avec des exigences de mémoire très dynamics (pensez à un navigateur Web), vous devriez évidemment avoir de la mémoire libre que vous n’utilisez plus dès que possible (par exemple, fermer un onglet / document / etc.) , mais il n’ya aucune raison de libérer quoi que ce soit lorsque l’utilisateur sélectionne les clics «exit», ce qui est réellement préjudiciable à l’expérience de l’utilisateur.

Pourquoi? Libérer de la mémoire nécessite de toucher la mémoire. Même si l’implémentation malloc de votre système ne stocke pas les métadonnées adjacentes aux blocs de mémoire alloués, vous allez probablement parcourir des structures récursives uniquement pour trouver tous les pointeurs dont vous avez besoin de libérer.

Supposons maintenant que votre programme a fonctionné avec un grand volume de données, mais qu’il n’en ait pas touché la plupart du temps (encore une fois, le navigateur Web en est un excellent exemple). Si l’utilisateur exécute beaucoup d’applications, une bonne partie de ces données a probablement été transférée sur le disque. Si vous quittez simplement (0) ou revenez de main, il quitte instantanément. Excellente expérience utilisateur. Si vous essayez de tout libérer, vous pouvez passer 5 secondes ou plus à échanger toutes les données, pour les jeter immédiatement après. Perte de temps de l’utilisateur. Déchets de la vie de la batterie de l’ordinateur portable. Déchets d’usure sur le disque dur.

Ce n’est pas seulement théorique. Chaque fois que je me retrouve avec trop d’applications chargées et que le disque commence à tomber, je ne pense même pas à cliquer sur “exit”. J’arrive à un terminal aussi vite que je peux et je tape killall -9 … parce que je sais que “exit” ne fera qu’empirer les choses.

Je suis sûr que quelqu’un peut trouver une raison de dire oui, mais ce ne sera pas moi. Au lieu de dire non, je vais dire que cela ne devrait pas être une question oui / non. Il existe des moyens de gérer ou de contenir les memory leaks, et de nombreux systèmes en ont.

Il y a des systèmes de la NASA sur des appareils qui quittent la terre pour planifier cela. Les systèmes redémarreront automatiquement de temps en temps pour que les memory leaks ne deviennent pas fatales à l’opération globale. Juste un exemple de confinement.

Si vous allouez de la mémoire et l’utilisez jusqu’à la dernière ligne de votre programme, ce n’est pas une fuite. Si vous allouez de la mémoire et que vous l’oubliez, même si la quantité de mémoire ne augmente pas, c’est un problème. Cette mémoire allouée mais non utilisée peut entraîner un ralentissement ou un échec des autres programmes.

Je peux compter d’une part sur le nombre de fuites “bénignes” que j’ai vues au fil du temps.

Donc, la réponse est un oui très qualifié.

Un exemple. Si vous avez une ressource singleton qui a besoin d’un tampon pour stocker une queue circulaire ou un fichier deque mais ne sait pas quelle taille doit avoir le tampon et ne peut pas se permettre le locking ou chaque lecteur, vous allouez un tampon exponentiel ne pas libérer les anciens entraînera une perte de mémoire par queue / deque. L’avantage de ces solutions est qu’elles accélèrent considérablement chaque access et peuvent modifier l’asymptotique des solutions multiprocesseurs en ne risquant jamais de provoquer un conflit.

J’ai vu cette approche très utile pour les choses avec des comptes très clairement définis, tels que les deques volants par CPU, et dans une moindre mesure dans le tampon utilisé pour tenir l’état singleton /proc/self/maps dans Hans Le ramasse-miettes conservateur de Boehm pour C / C ++, qui sert à détecter les ensembles de racines, etc.

Bien que techniquement une fuite, ces deux cas sont limités en taille et, dans le cas du travail deque volant circulaire, il y a un gain de performance énorme en échange d’un facteur 2 d’augmentation de l’utilisation de la mémoire pour les files d’attente.

Si vous allouez un tas de tas au début de votre programme, et que vous ne le libérez pas lorsque vous quittez, ce n’est pas une fuite de mémoire en soi. Une fuite de mémoire se produit lorsque votre programme passe en boucle sur une section de code, et que ce code alloue un tas puis “perd la trace” de celui-ci sans le libérer.

En fait, il n’est pas nécessaire de faire des appels à free () ou de supprimer juste avant de quitter. A la sortie du processus, tout son espace mémoire est récupéré par le système d’exploitation (c’est certainement le cas avec POSIX. Sur les autres systèmes d’exploitation, en particulier ceux embarqués, YMMV).

La seule précaution que je ferais de ne pas libérer de la mémoire au moment de la sortie est que si jamais vous réorganisez votre programme pour qu’il devienne, par exemple, un service en attente d’entrée, effectue ce que vous faites. un autre appel de service, alors ce que vous avez codé peut se transformer en une fuite de mémoire.

c’est tellement spécifique au domaine que cela ne vaut guère la peine de répondre. utilisez votre tête effrayante.

  • système d’exploitation de la navette spatiale: non, aucune fuite de mémoire autorisée
  • code de développement rapide de preuve de concept: réparer toutes les memory leaks est une perte de temps.

et il y a un spectre de situations intermédiaires.

le coût d’opportunité ($$$) de retarder la sortie d’un produit pour résoudre tous les problèmes, à l’exception des memory leaks les plus graves, réduit généralement le sentiment de “négligence ou de manque de professionnalisme”. Votre patron vous paye pour lui faire gagner de l’argent, pas pour avoir des sentiments chauds.

Vous devez d’abord comprendre qu’il y a une grande différence entre une fuite de mémoire perçue et une fuite de mémoire réelle. Très fréquemment, les outils d’parsing signalent de nombreuses erreurs rouges et étiquettent quelque chose comme ayant été divulgué (mémoire ou ressources telles que les poignées, etc.) là où il n’en est pas. Souvent, cela est dû à l’architecture de l’outil d’parsing. Par exemple, certains outils d’parsing signaleront les objects d’exécution comme des memory leaks car ils ne voient jamais ces objects libérés. Mais la désallocation se produit dans le code d’arrêt du moteur d’exécution, que l’outil d’parsing risque de ne pas pouvoir voir.

Cela dit, il y aura toujours des moments où vous aurez des memory leaks réelles qui sont très difficiles à trouver ou très difficiles à corriger. Alors maintenant, la question est de savoir s’il est toujours possible de les laisser dans le code?

La réponse idéale est “non, jamais”. Une réponse plus pragmatique pourrait être “non, presque jamais”. Très souvent, dans la vraie vie, vous avez un nombre limité de ressources et de temps pour résoudre et une liste infinie de tâches. Lorsqu’une des tâches consiste à éliminer les memory leaks, la loi des rendements décroissants entre très souvent en ligne de compte. Vous pourriez éliminer par exemple 98% de toutes les memory leaks dans une application en une semaine, mais les 2% restants pourraient prendre des mois. Dans certains cas, il peut même être impossible d’éliminer certaines fuites en raison de l’architecture de l’application sans une refonte majeure du code. Vous devez évaluer les coûts et les avantages de l’élimination des 2% restants.

Dans ce genre de question, le contexte est tout. Personnellement, je ne supporte pas les fuites, et dans mon code, je me donne beaucoup de mal pour les réparer si elles arrivent, mais ça ne vaut pas toujours la peine de réparer une fuite, et quand les gens me payent à l’heure Je leur ai dit que cela ne valait pas ma peine de réparer une fuite dans leur code. Laisse moi te donner un exemple:

Je sortingais un projet, je faisais du perf et je corrigeais beaucoup de bugs. Il y a eu une fuite lors de l’initialisation des applications que j’ai repérée et parfaitement comprise. Le réparer correctement aurait nécessité une journée ou deux de refactorisation d’un morceau de code fonctionnel. J’aurais pu faire quelque chose de hacky (comme mettre la valeur dans un global et le saisir à un moment donné, je sais qu’il n’était plus utilisé pour libérer), mais cela aurait simplement causé plus de confusion au prochain gars qui devait toucher le code.

Personnellement, je n’aurais pas écrit le code de cette façon, mais la plupart d’entre nous ne travaillons pas toujours sur des bases de code parfaitement conçues, et il faut parfois regarder ces choses de manière pragmatique. La quantité de temps qu’il aurait fallu pour réparer cette fuite de 150 octets pourrait être consacrée à des améliorations algorithmiques qui réduiraient les mégaoctets de RAM.

En fin de compte, j’ai décidé que la fuite de 150 octets pour une application qui utilisait un concert de RAM et fonctionnait sur une machine dédiée ne valait pas la peine d’être corrigée. J’ai donc écrit un commentaire disant qu’il fallait changer pour corriger ça, et pourquoi ça ne valait pas la peine à l’époque.

Alors que la plupart des réponses se concentrent sur les memory leaks réelles (qui ne sont jamais correctes, car elles sont un signe de codage bâclé), cette partie de la question me semble plus intéressante:

Que faire si vous allouez de la mémoire et l’utilisez jusqu’à la toute dernière ligne de code de votre application (par exemple, le déconstructeur d’un object global)? Tant que la consommation de mémoire n’augmente pas avec le temps, est-il correct de faire confiance au système d’exploitation pour libérer votre mémoire lorsque votre application se termine (sous Windows, Mac et Linux)? Voulez-vous même considérer cela comme une véritable fuite de mémoire si la mémoire était utilisée de manière continue jusqu’à ce qu’elle soit libérée par le système d’exploitation.

Si la mémoire associée est utilisée, vous ne pouvez pas la libérer avant la fin du programme. Que le free soit fait par la sortie du programme ou par le système d’exploitation n’a pas d’importance. Tant que cela est documenté, ce changement n’introduit pas de memory leaks réelles, et tant qu’il n’y a pas de fonction destructeur C ou de nettoyage C impliquée dans l’image. Un fichier non fermé peut être révélé par le biais d’un object FILE fui, mais un fichier fclose () manquant peut également empêcher le vidage du tampon.

Donc, en ce qui concerne le cas original, il est tout à fait correct en soi, à tel point que Valgrind, l’un des détecteurs de fuites les plus puissants, ne traitera ces fuites que sur demande. Sur Valgrind, lorsque vous écrasez un pointeur sans le libérer au préalable, il est considéré comme une fuite de mémoire, car il est plus probable que cela se reproduise et que le tas se développe sans fin.

Ensuite, il n’y a pas de blocs de mémoire libres encore accessibles. On pourrait s’assurer de les libérer tous à la sortie, mais ce n’est qu’une perte de temps en soi. Le point est de savoir s’ils pourraient être libérés avant . Diminuer la consommation de mémoire est utile dans tous les cas.

Même si vous êtes sûr que votre fuite de mémoire «connue» ne causera pas de dégâts, ne le faites pas. Au mieux, cela vous ouvrira la voie à une erreur similaire et probablement plus grave à un moment et à un endroit différents.

Pour moi, demander ceci est comme interroger “Puis-je briser le feu rouge à 3 heures du matin quand personne n’est autour?”. Bien sûr, cela ne posera peut-être pas de problème à ce moment-là mais cela vous fournira un levier pour faire la même chose en heure de pointe!

Je suis surpris de voir tant de définitions incorrectes de ce qu’est une fuite de mémoire. Sans définition concrète, une discussion sur la question de savoir si c’est une mauvaise chose ou non ne mènera nulle part.

Comme certains commentateurs l’ont souligné à juste titre, une fuite de mémoire ne se produit que lorsque la mémoire allouée par un processus est hors de scope dans la mesure où le processus n’est plus en mesure de le référencer ou de le supprimer.

Un processus qui prend de plus en plus de mémoire ne fuit pas nécessairement. Tant qu’il est capable de référencer et de désallouer cette mémoire, il rest sous le contrôle explicite du processus et n’a pas fui. Le processus peut être mal conçu, en particulier dans le contexte d’un système où la mémoire est limitée, mais ce n’est pas la même chose qu’une fuite. À l’inverse, en perdant la scope d’un tampon de 32 octets, par exemple, il s’agit toujours d’une fuite, même si la quantité de mémoire perdue est faible. Si vous pensez que cela est insignifiant, attendez que quelqu’un achemine un algorithme autour de votre appel de bibliothèque et l’appelle 10 000 fois.

Je ne vois aucune raison de permettre des fuites dans votre propre code, aussi petit soit-il. Modern programming languages such as C and C++ go to great lengths to help programmers prevent such leaks and there is rarely a good argument not to adopt good programming techniques – especially when coupled with specific language facilities – to prevent leaks.

As regards existing or third party code, where your control over quality or ability to make a change may be highly limited, depending on the severity of the leak, you may be forced to accept or take mitigating action such as restarting your process regularly to reduce the effect of the leak.

It may not be possible to change or replace the existing (leaking) code, and therefore you may be bound to accept it. However, this is not the same as declaring that it’s OK.

Its really not a leak if its intentional and its not a problem unless its a significant amount of memory, or could grow to be a significant amount of memory. Its fairly common to not cleanup global allocations during the lifetime of a program. If the leak is in a server or long running app, grows over time, then its a problem.

I think you’ve answered your own question. The biggest drawback is how they interfere with the memory leak detection tools, but I think that drawback is a HUGE drawback for certain types of applications.

I work with legacy server applications that are supposed to be rock solid but they have leaks and the globals DO get in the way of the memory detection tools. It’s a big deal.

In the book “Collapse” by Jared Diamond, the author wonders about what the guy was thinking who cut down the last tree on Easter Island, the tree he would have needed in order to build a canoe to get off the island. I wonder about the day many years ago when that first global was added to our codebase. THAT was the day it should have been caught.

I see the same problem as all scenario questions like this: What happens when the program changes, and suddenly that little memory leak is being called ten million times and the end of your program is in a different place so it does matter? If it’s in a library then log a bug with the library maintainers, don’t put a leak into your own code.

I’ll answer no.

In theory, the operating system will clean up after you if you leave a mess (now that’s just rude, but since computers don’t have feelings it might be acceptable). But you can’t anticipate every possible situation that might occur when your program is run. Therefore (unless you are able to conduct a formal proof of some behaviour), creating memory leaks is just irresponsible and sloppy from a professional point of view.

If a third-party component leaks memory, this is a very strong argument against using it, not only because of the imminent effect but also because it shows that the programmers work sloppily and that this might also impact other mesortingcs. Now, when considering legacy systems this is difficult (consider web browsing components: to my knowledge, they all leak memory) but it should be the norm.

Historically, it did matter on some operating systems under some edge cases. These edge cases could exist in the future.

Here’s an example, on SunOS in the Sun 3 era, there was an issue if a process used exec (or more traditionally fork and then exec), the subsequent new process would inherit the same memory footprint as the parent and it could not be shrunk. If a parent process allocated 1/2 gig of memory and didn’t free it before calling exec, the child process would start using that same 1/2 gig (even though it wasn’t allocated). This behavior was best exhibited by SunTools (their default windowing system), which was a memory hog. Every app that it spawned was created via fork/exec and inherited SunTools footprint, quickly filling up swap space.

This was already discussed ad nauseam . Bottom line is that a memory leak is a bug and must be fixed. If a third party library leaks memory, it makes one wonder what else is wrong with it, no? If you were building a car, would you use an engine that is occasionally leaking oil? After all, somebody else made the engine, so it’s not your fault and you can’t fix it, right?

Generally a memory leak in a stand alone application is not fatal, as it gets cleaned up when the program exits.

What do you do for Server programs that are designed so they don’t exit?

If you are the kind of programmer that does not design and implement code where the resources are allocated and released correctly, then I don’t want anything to do with you or your code. If you don’t care to clean up your leaked memory, what about your locks? Do you leave them hanging out there too? Do you leave little turds of temporary files laying around in various directories?

Leak that memory and let the program clean it up? No. Absolutely not. It’s a bad habit, that leads to bugs, bugs, and more bugs.

Clean up after yourself. Yo momma don’t work here no more.

As a general rule, if you’ve got memory leaks that you feel you can’t avoid, then you need to think harder about object ownership.

But to your question, my answer in a nutshell is In production code, yes. During development, no . This might seem backwards, but here’s my reasoning:

In the situation you describe, where the memory is held until the end of the program, it’s perfectly okay to not release it. Once your process exits, the OS will clean up anyway. In fact, it might make the user’s experience better: In a game I’ve worked on, the programmers thought it would be cleaner to free all the memory before exiting, causing the shutdown of the program to take up to half a minute! A quick change that just called exit() instead made the process disappear immediately, and put the user back to the desktop where he wanted to be.

However, you’re right about the debugging tools: They’ll throw a fit, and all the false positives might make finding your real memory leaks a pain. And because of that, always write debugging code that frees the memory, and disable it when you ship.

No, you should not have leaks that the OS will clean for you. The reason (not mentioned in the answers above as far as I could check) is that you never know when your main() will be re-used as a function/module in another program . If your main() gets to be a frequently-called function in another persons’ software – this software will have a memory leak that eats memory over time.

KIV

I agree with vfilby – it depends. In Windows, we treat memory leaks as relatively serous bugs. But, it very much depends on the component.

For example, memory leaks are not very serious for components that run rarely, and for limited periods of time. These components run, do theire work, then exit. When they exit all their memory is freed implicitly.

However, memory leaks in services or other long run components (like the shell) are very serious. The reason is that these bugs ‘steal’ memory over time. The only way to recover this is to restart the components. Most people don’t know how to restart a service or the shell – so if their system performance suffers, they just reboot.

So, if you have a leak – evaluate its impact two ways

  1. To your software and your user’s experience.
  2. To the system (and the user) in terms of being frugal with system resources.
  3. Impact of the fix on maintenance and reliability.
  4. Likelihood of causing a regression somewhere else.

Foredecker

I guess it’s fine if you’re writing a program meant to leak memory (ie to test the impact of memory leaks on system performance).