J'ai rencontré plusieurs fois des fuites de mémoire. Habituellement, quand je suis malloc
comme s'il n'y avait pas de lendemain, ou que je pendais comme du FILE *
linge sale. Je suppose généralement (lire: espère désespérément) que toute la mémoire est nettoyée au moins lorsque le programme se termine. Y a-t-il des situations où la mémoire perdue ne sera pas collectée lorsque le programme se termine ou se bloque?
Si la réponse varie considérablement d'un langage à l'autre, concentrons-nous sur C (++).
Veuillez noter l'utilisation hyperbolique de la phrase «comme s'il n'y avait pas de lendemain» et «pendant ... comme du linge sale». Un danger * malloc
* peut blesser ceux que vous aimez. Veuillez également faire preuve de prudence avec le linge sale.
la source
calloc
aimer qu'il n'y ait pas de lendemain. Excellent.Réponses:
Non. Les systèmes d'exploitation libèrent toutes les ressources détenues par les processus lorsqu'ils se terminent.
Cela s'applique à toutes les ressources gérées par le système d'exploitation: mémoire, fichiers ouverts, connexions réseau, poignées de fenêtre ...
Cela dit, si le programme s'exécute sur un système embarqué sans système d'exploitation, ou avec un système d'exploitation très simple ou bogué, la mémoire peut être inutilisable jusqu'au redémarrage. Mais si vous étiez dans cette situation, vous ne poseriez probablement pas cette question.
Le système d'exploitation peut mettre du temps à libérer certaines ressources. Par exemple, le port TCP utilisé par un serveur réseau pour accepter les connexions peut mettre quelques minutes à se libérer, même s'il est correctement fermé par le programme. Un programme en réseau peut également contenir des ressources distantes telles que des objets de base de données. Le système distant doit libérer ces ressources lorsque la connexion réseau est perdue, mais cela peut prendre encore plus de temps que le système d'exploitation local.
la source
ipcrm
pour le nettoyage manuel, linux.die.net/man/8/ipcrm .La norme C ne spécifie pas que la mémoire allouée par
malloc
est libérée lorsque le programme se termine. Ceci fait par le système d'exploitation et tous les systèmes d'exploitation (généralement ceux-ci sont dans le monde embarqué) libèrent la mémoire lorsque le programme se termine.la source
main
retours, toute la mémoire allouée parmalloc
est libérée. Par exemple, il indique que tous les fichiers ouverts sont fermés avant la fin du programme. Pour la mémoire allouée mymalloc
, il n'est tout simplement pas spécifié. Maintenant, bien sûr, ma phrase concernant le système d'exploitation décrit ce qui est généralement fait et non ce que la norme prescrit, car elle ne spécifie rien à ce sujet.std::atexit
considère également la terminaison du programme viastd::exit
, et puis il y a aussistd::abort
et (spécifique à C ++)std::terminate
.atexit
ne serait pas utilisable. :-)Comme toutes les réponses ont couvert la plupart des aspects de votre question par rapport aux systèmes d'exploitation modernes, mais historiquement, il y en a une qui mérite d'être mentionnée si vous avez déjà programmé dans le monde DOS. Les programmes Terminant et Stay Resident (TSR) retournaient généralement le contrôle du système mais résideraient dans la mémoire qui pourrait être réactivée par une interruption logicielle / matérielle. Il était normal de voir des messages comme "mémoire insuffisante! Essayez de décharger certains de vos TSR" lorsque vous travaillez sur ces systèmes d'exploitation.
Donc, techniquement, le programme se termine , mais comme il réside toujours en mémoire, aucune fuite de mémoire ne sera libérée à moins que vous ne déchargiez le programme.
Vous pouvez donc considérer cela comme un autre cas en dehors des systèmes d'exploitation qui ne récupèrent pas de mémoire, soit parce que c'est bogué, soit parce que le système d'exploitation intégré est conçu pour le faire.
Je me souviens d'un autre exemple. Le système de contrôle des informations client (CICS), un serveur de transactions qui s'exécute principalement sur des mainframes IBM est pseudo-conversationnel. Lorsqu'il est exécuté, il traite les données saisies par l'utilisateur, génère un autre ensemble de données pour l'utilisateur, le transfère au nœud de terminal utilisateur et se termine. Lors de l'activation de la touche d'attention, il revient à nouveau pour traiter un autre ensemble de données. En raison de la façon dont il se comporte, techniquement encore, le système d'exploitation ne récupérera pas la mémoire des programmes CICS terminés, à moins que vous ne recycliez le serveur de transactions CICS.
la source
Comme les autres l'ont dit, la plupart des systèmes d'exploitation récupéreront la mémoire allouée à la fin du processus (et probablement d'autres ressources telles que les sockets réseau, les descripteurs de fichiers, etc.).
Cela dit, la mémoire n'est peut-être pas la seule chose dont vous devez vous soucier lorsque vous traitez avec new / delete (au lieu de raw malloc / free). La mémoire allouée dans new peut être récupérée, mais les choses qui peuvent être faites dans les destructeurs des objets ne se produiront pas. Peut-être que le destructeur d'une classe écrit une valeur sentinelle dans un fichier lors de la destruction. Si le processus se termine, le descripteur de fichier peut être vidé et la mémoire récupérée, mais cette valeur sentinelle ne sera pas écrite.
Morale de l'histoire, nettoyez toujours après vous-même. Ne laissez pas les choses pendre. Ne comptez pas sur le nettoyage du système d'exploitation après vous. Nettoyez après vous.
la source
kill -9
fan moins brillant ne se présente ...)std::exit
appellera des dtors,std::abort
pas, des exceptions non interceptées pourraient.Cela dépendra plus probablement du système d'exploitation que de la langue. En fin de compte, tout programme dans n'importe quelle langue obtiendra sa mémoire du système d'exploitation.
Je n'ai jamais entendu parler d'un système d'exploitation qui ne recycle pas la mémoire lorsqu'un programme se ferme / se bloque. Donc, si votre programme a une limite supérieure sur la mémoire qu'il doit allouer, alors simplement allouer et ne jamais libérer est parfaitement raisonnable.
la source
Si le programme est un jour transformé en un composant dynamique ("plugin") qui est chargé dans l'espace d'adressage d'un autre programme, cela sera gênant, même sur un système d'exploitation avec une gestion de mémoire ordonnée. Nous n'avons même pas à penser au code porté sur des systèmes moins performants.
D'un autre côté, la libération de toute la mémoire peut avoir un impact sur les performances du nettoyage d'un programme.
Un programme sur lequel je travaillais, un certain cas de test a nécessité 30 secondes ou plus pour que le programme se termine, car il revenait à travers le graphique de toute la mémoire dynamique et le libérait morceau par morceau.
Une solution raisonnable consiste à avoir la capacité là-bas et à la couvrir de cas de test, mais à la désactiver dans le code de production afin que l'application se ferme rapidement.
la source
Tous les systèmes d'exploitation méritant le titre nettoieront le désordre causé par votre processus après la résiliation. Mais il y a toujours des événements imprévus, que se passe-t-il s'il s'est vu refuser l'accès d'une manière ou d'une autre et qu'un pauvre programmeur n'a pas prévu la possibilité et qu'il ne réessaye pas un peu plus tard? Toujours plus sûr de simplement nettoyer vous-même SI les fuites de mémoire sont essentielles à la mission - sinon, cela ne vaut pas vraiment la peine OMI si cet effort est coûteux.
Edit: Vous devez nettoyer les fuites de mémoire si elles sont en place où elles vont s'accumuler, comme dans les boucles. Les fuites de mémoire dont je parle sont celles qui s'accumulent en temps constant tout au long du programme, si vous avez une fuite de toute autre sorte, ce sera probablement un problème sérieux tôt ou tard.
En termes techniques si vos fuites sont de «complexité» mémoire O (1) elles sont correctes dans la plupart des cas, O (logn) déjà désagréable (et dans certains cas fatal) et O (N) + intolérable.
la source
La mémoire partagée sur les systèmes compatibles POSIX persiste jusqu'à ce que shm_unlink soit appelé ou que le système soit redémarré.
la source
Si vous avez une communication interprocessus, cela peut amener d'autres processus à ne jamais terminer et consommer des ressources en fonction du protocole.
Pour donner un exemple, j'ai déjà expérimenté l'impression sur une imprimante PDF en Java lorsque j'ai arrêté la JVM au milieu d'un travail d'impression, le processus de spoule PDF est resté actif et j'ai dû le tuer dans le gestionnaire de tâches avant de pouvoir relancez l'impression.
la source