web-dev-qa-db-fra.com

Est-ce une perte de temps de libérer des ressources avant de quitter un processus?

Prenons un programme fictif qui crée une liste chaînée dans le tas, et à la fin du programme, il y a une boucle qui libère tous les nœuds, puis se ferme. Dans ce cas, disons que la liste chaînée ne fait que 500 Ko de mémoire et qu'aucune gestion d'espace spéciale n'est requise.

  • Est-ce une perte de temps, car le système d'exploitation le fera de toute façon?
  • Y aura-t-il un comportement différent plus tard?
  • Est-ce différent selon la version du système d'exploitation?

Je suis principalement intéressé par les systèmes basés sur UNIX, mais toute information sera appréciée. J'ai eu aujourd'hui ma première leçon de cours OS et je me pose des questions à ce sujet maintenant.

Edit: Étant donné que beaucoup de gens ici sont préoccupés par les effets secondaires et les "bonnes pratiques de programmation" générales et ainsi de suite. Tu as raison! Je suis d'accord à 100% avec vos déclarations. Mais ma question n'est qu'hypothétique, je veux savoir comment l'OS gère cela. Veuillez donc laisser de côté des choses comme "trouver d'autres bogues lors de la libération de toute la mémoire".

66
Ramzi Kahil

OK, je viens de recevoir un e-mail de mon instructeur, avec une réponse très bonne et raisonnable. C'est ici:

Salut Ramzi,

Merci pour le lien vers le fil de messages intéressant que vous avez commencé.

Selon notre discussion, malloc fonctionne sur la mémoire virtuelle du processus. Ainsi, lorsque le processus meurt, son espace d'adressage virtuel "disparaît" et toute mémoire physique qui lui est mappée est libérée. Par conséquent, ignorer les "bonnes pratiques d'ingénierie logicielle" et une telle désallocation dynamique de mémoire juste avant de quitter un processus est en effet une perte de temps.

(Inutile de dire que ce n'est pas le cas lorsqu'un seul thread se termine mais que d'autres threads de ce processus continuent de s'exécuter.)

Donc, selon ceci:

  • C'est une perte de temps
  • N'aura pas d'effets ultérieurs
  • Est indépendant des versions du système d'exploitation.
18
Ramzi Kahil

Mon principal problème avec votre approche est qu'un outil de détection de fuite (comme Valgrind) le signalera et vous commencerez à l'ignorer. Puis, un jour, une véritable fuite peut apparaître et vous ne la remarquerez jamais à cause de tout le bruit.

69
Nemanja Trifunovic

Une fois, j'ai dû implémenter un algorithme utilisant des deques qui étaient alloués dynamiquement. Je me demandais également si j'avais besoin de désallouer toutes les données allouées à la sortie.

J'ai quand même décidé d'implémenter la désallocation et j'ai découvert que le programme s'est écrasé pendant la désallocation. En analysant le crash, j'ai trouvé une erreur dans l'implémentation de la structure de données et des algorithmes principaux (une fuite de mémoire).

Les leçons que j'ai apprises étaient les suivantes:

  1. Implémentez toujours la désallocation pour les données que vous allouez, ce qui la rend plus réutilisable au cas où vous souhaiteriez intégrer votre code dans un système plus grand.
  2. La désallocation peut servir de vérification supplémentaire que vos données allouées sont dans un état cohérent lors de leur publication.

Juste mes 2 cents.

MODIFIER

Petite précision: Bien sûr, toute la mémoire allouée à un processus est libérée à la fin du processus, donc si la seule exigence est de libérer la mémoire allouée, le faire explicitement est en effet une perte de temps.

41
Giorgio

Libérez toujours vos ressources. Libérer toutes vos ressources est important car c'est le seul moyen de détecter efficacement les fuites. Pour le projet sur lequel je travaille, j'ai même des wrappers autour de malloc/realloc/free pour insérer des canaris, suivre des statistiques, etc; simplement pour détecter les problèmes plus tôt.

Cependant, à l'exception de la détection des fuites, pour les ressources qui sont libérées à la sortie (pas avant), c'est une perte de temps. Le système d'exploitation doit être en mesure de le libérer (par exemple, dans le cas où le processus se bloque, ou même simplement en libérant RAM utilisé pour le code du processus); et le système d'exploitation devrait être en mesure de le libérer plus rapidement que vous peut partir de l'espace utilisateur car le noyau fera "en gros" plutôt que "au coup par coup", et il y a moins de transitions entre le noyau et le processus impliqué.

Heureusement, vous n'avez pas à choisir d'une manière ou d'une autre. Si vous voulez vous assurer que votre code est correct (et vous le faites), mais que vous voulez également les meilleures performances possibles, faites quelque chose comme:

#ifndef FAST_EXIT
    free(stuff);
#endif
13
Brendan

La routine de nettoyage peut être utile si vous le faites régulièrement pour regagner de l'espace, ou pour prouver que vous êtes en mesure de récupérer exactement autant de nœuds que vous avez alloué, pour vérifier qu'il n'y a pas de fuites de mémoire. Mais comme Housekeeping immédiatement avant la fin du processus, cela n'a aucun sens, car le système d'exploitation reprend le contrôle de toute l'arène de la mémoire à cet instant.

8
Kilian Foth

Y aura-t-il un comportement différent plus tard?

Il y a une question critique liée à celle-ci que vous devez vous poser:

Est-ce que quelqu'un utilisera ce code à nouveau pour une raison quelconque?

Si jamais la réponse pouvait être oui, que le code soit utilisé seul ou en tant que partie d'un système plus vaste, vous avez créé une mine monumentale qui fuit une mine pour que la prochaine personne puisse marcher dessus.

Il est très difficile de se rappeler au cours de vos cours que vous apprenez à créer des logiciels que d'autres personnes vont utiliser , y compris future-you (plutôt que simplement résoudre le problème des devoirs du jour). Cela signifie que vous devez respecter certains comportements de programmation de base, notamment: redonner les ressources lorsque vous en avez terminé.

4
Bob Cross

Si vous implémentez votre propre type de données "liste liée", ne pas écrire de routine de nettoyage/déconstructeur vous donnera plus de maux de tête à long terme que vous ne le pensez.

Sans code de nettoyage, réutiliser ce que vous avez écrit sera beaucoup plus difficile car votre type ne peut pas être utilisé sans faire attention (par exemple, ne les créez jamais dans une fonction ou une boucle, mais de préférence exclusivement dans main).

Faites-vous plaisir à vous-même et à tous les autres et écrivez-vous simplement list_cleanup ou ~List.

2
Benjamin Bannier

Sur les systèmes multi-utilisateurs, le système d'exploitation libérera toujours ces ressources, car ce serait un risque pour la sécurité s'il ne le faisait pas. Le contenu de votre mémoire peut se terminer par le processus de quelqu'un d'autre!

1
MSalters

Les routines de nettoyage peuvent avoir des bogues comme tout autre code. Un triste spectacle est un programme qui fait ce que vous voulez, sauf qu'il se bloque ou se bloque à la sortie. La pratique générale consiste à faire nettoyer le code après lui-même, mais le nettoyage de la mémoire à la sortie du processus est un cas où vous n'avez pas à le faire.

1
Sonia

Presque toujours oui. Sémaphores à mémoire partagée et ressources de serveur UDP gratuits (le système d'exploitation ne sait pas comment informer les serveurs UDP connectés que vous avez terminé).

1
Joshua

Je nettoie toujours les ressources à la sortie normale. C'est un contrôle de sécurité que mes appels d'allocation/désallocation de ressources sont bien effectués. Cette vérification m'a alerté à plusieurs reprises sur des bogues cachés. C'est comme équilibrer les livres d'une entreprise à la fin de la journée.

Il peut y avoir des cas Edge tels que @MSalter décrit dans son commentaire, mais même cela me ferait généralement commencer à regarder la gestion de la mémoire personnalisée, plutôt que de simplement laisser le système d'exploitation nettoyer et d'espérer le meilleur.

1
Charles E. Grant

Si vous êtes sûr à 100% qu'aucun autre processus ne fait référence à votre liste liée et aux nœuds qui s'y trouvent, OK.

100% est cependant un chiffre assez élevé. Votre liste a-t-elle été référencée par un code de persistance en cours de mise en commun? Un composant d'interface utilisateur a-t-il toujours une poignée dessus? N'importe quoi autrement?

Les fuites de mémoire ne se produisent généralement pas exprès.

0
Matthew Flynn

Le problème est qu'aujourd'hui c'est un nœud de liste liée, et demain, c'est une ressource que le système d'exploitation ne peut pas nettoyer par lui-même. Est-il rapide et sûr de quitter le système d'exploitation pour nettoyer la mémoire du tas? Oui. Mais est-ce que cela en fait une bonne idée? Pas nécessairement.

0
DeadMG