Disons que j'ai le code C suivant:
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
Lorsque je compile et exécute ce programme C, c'est-à-dire après avoir alloué de l'espace en mémoire, cette mémoire que j'ai allouée sera-t-elle toujours allouée (c'est-à-dire en prenant essentiellement de l'espace) après avoir quitté l'application et le processus se termine?
Cela dépend du système d'exploitation. La majorité des systèmes d'exploitation modernes (et tous les principaux) libéreront de la mémoire non libérée par le programme à la fin.
S'appuyer sur cela est une mauvaise pratique et il vaut mieux la libérer explicitement. Le problème n'est pas seulement que votre code semble mauvais. Vous pouvez décider d'intégrer votre petit programme dans un programme plus long et plus long. Puis, un peu plus tard, vous devez passer des heures à rechercher les fuites de mémoire.
S'appuyer sur une caractéristique d'un système d'exploitation rend également le code moins portable.
En général, les systèmes d'exploitation à usage général modernes nettoient après les processus terminés. Cela est nécessaire car l'alternative est que le système perd des ressources au fil du temps et nécessite un redémarrage en raison de programmes mal écrits ou simplement de bogues qui fuient rarement les ressources.
De toute façon, le fait que votre programme libère explicitement ses ressources peut être une bonne pratique pour diverses raisons, telles que:
Cependant, voici une raison pour ignorer la libération de mémoire: arrêt efficace. Par exemple, supposons que votre application contienne un grand cache en mémoire. Si, à sa sortie, il parcourt toute la structure du cache et le libère une pièce à la fois, cela ne sert à rien et gaspille les ressources. En particulier, considérez le cas où les pages de mémoire contenant votre cache ont été échangées sur le disque par le système d'exploitation; en parcourant la structure et en la libérant, vous ramenez toutes ces pages en mémoire en une seule fois , gaspillant beaucoup de temps et d'énergie sans aucun avantage réel, et peut-être même provoquer l'échange d'autres programmes sur le système!
À titre d'exemple connexe, il existe des serveurs hautes performances qui fonctionnent en créant un processus pour chaque demande, puis en le quittant une fois terminé; de cette façon, ils n'ont même pas besoin de suivre l'allocation de mémoire , et de ne jamais faire de libération ou de récupération de place du tout, car tout disparaît mémoire libre du système d'exploitation à la fin du processus. (Le même genre de chose peut être fait dans un processus en utilisant un allocateur de mémoire personnalisé, mais nécessite une programmation très soignée; essentiellement faire sa propre notion de "processus légers" dans le processus du système d'exploitation.)
Mes excuses pour avoir posté si longtemps après le dernier message sur ce fil.
Un point supplémentaire. Tous les programmes ne parviennent pas à des sorties gracieuses. Les plantages et les touches Ctrl-C, etc. entraîneront la fermeture incontrôlée d'un programme. Si votre système d'exploitation ne libérait pas votre tas, nettoyait votre pile, supprimait des variables statiques, etc., vous risqueriez de planter votre système contre les fuites de mémoire ou pire.
Hormis cela, les plantages/interruptions dans Ubuntu, et je soupçonne que tous les autres systèmes d'exploitation modernes, ont des problèmes avec les ressources "gérées". Les sockets, fichiers, périphériques, etc. peuvent rester "ouverts" lorsqu'un programme se termine/se bloque. également une bonne pratique pour fermer quoi que ce soit avec une "poignée" ou un "descripteur" dans le cadre de votre nettoyage avant une sortie en douceur.
Je développe actuellement un programme qui utilise fortement les sockets. Quand je suis coincé dans un blocage, je dois en faire un Ctrl-C, donc, échouant mes prises. J'ai ajouté un std :: vector pour collecter une liste de toutes les sockets ouvertes et un gestionnaire de sigaction qui attrape sigint et sigterm. Le gestionnaire parcourt la liste et ferme les sockets. Je prévois de faire une routine de nettoyage similaire à utiliser avant les lancers qui conduira à une interruption prématurée.
Quelqu'un veut-il commenter cette conception?
Ce qui se passe ici (dans un système d'exploitation moderne), c'est que votre programme s'exécute à l'intérieur de son propre "processus". Il s'agit d'une entité de système d'exploitation dotée de son propre espace d'adressage, de descripteurs de fichiers, etc. Vos appels malloc
allouent de la mémoire à partir du "tas" ou des pages de mémoire non allouées qui sont affectées à votre processus.
Lorsque votre programme se termine, comme dans cet exemple, toutes les ressources affectées à votre processus sont simplement recyclées/détruites par le système d'exploitation. Dans le cas de la mémoire, toutes les pages de mémoire qui vous sont attribuées sont simplement marquées comme "libres" et recyclées pour l'utilisation d'autres processus. Les pages sont un concept de niveau inférieur à ce que malloc gère - en conséquence, les spécificités de malloc/free sont tout simplement effacées lorsque tout est nettoyé.
C'est l'équivalent moral de, lorsque vous avez terminé d'utiliser votre ordinateur portable et que vous souhaitez le donner à un ami, vous ne vous souciez pas de supprimer individuellement chaque fichier. Vous formatez simplement le disque dur.
Cela dit, comme le notent tous les autres répondeurs, s’en remettre à ce n’est pas une bonne pratique:
Oui. L'OS nettoie les ressources. Eh bien ... les anciennes versions de NetWare ne le faisaient pas.
Edit: Comme San Jacinto l'a souligné, il existe certainement des systèmes (à part NetWare) qui ne font pas cela. Même dans les programmes jetables, j'essaie de prendre l'habitude de libérer toutes les ressources juste pour garder l'habitude.
Oui, le système d'exploitation libère toute la mémoire à la fin du processus.
Cela dépend, les systèmes d'exploitation le nettoieront généralement pour vous, mais si vous travaillez par exemple sur un logiciel intégré, il risque de ne pas être publié.
Assurez-vous simplement de le libérer, cela peut vous faire gagner beaucoup de temps plus tard lorsque vous voudrez peut-être l'intégrer à un grand projet.
Cela dépend vraiment du système d'exploitation, mais pour tous les systèmes d'exploitation que vous rencontrerez, l'allocation de mémoire disparaîtra à la fin du processus.
Je pense que la libération directe est la meilleure. Un comportement indéfini est la pire chose, donc si vous avez accès alors qu'il est encore défini dans votre processus, faites-le, il y a beaucoup de bonnes raisons que les gens ont données pour cela.
Quant à savoir où, ou si, j'ai trouvé que dans W98, la vraie question était "quand" (je n'ai pas vu de message soulignant cela). Un petit programme de modèle (pour MIDI SysEx, en utilisant divers espaces malloc'd) libérerait de la mémoire dans le bit WM_DESTROY du WndProc, mais quand je l'ai transplanté dans un programme plus grand, il s'est écrasé à la sortie . J'ai supposé que cela signifiait que j'essayais de libérer ce que le système d'exploitation avait déjà libéré lors d'un nettoyage plus important. Si je l'ai fait sur WM_CLOSE, puis appelé DestroyWindow (), tout a bien fonctionné, une sortie de nettoyage instantanée.
Bien que ce ne soit pas exactement la même chose que MIDI, il y a une similitude en ce qu'il est préférable de garder le processus intact, de nettoyer complètement, puis de quitter. Avec des morceaux de mémoire modestes, c'est très rapide J'ai constaté que de nombreux petits tampons fonctionnaient plus rapidement en fonctionnement et en nettoyage que moins de grands.
Des exceptions peuvent exister, comme quelqu'un l'a dit en évitant de retirer de gros morceaux de mémoire d'un fichier d'échange sur le disque, mais même cela peut être minimisé en gardant plus et plus petits espaces alloués.