web-dev-qa-db-fra.com

Jusqu'où les fuites de mémoire peuvent-elles aller?

J'ai rencontré des fuites de mémoire à plusieurs reprises. Habituellement, quand je suis malloc- comme s'il n'y avait pas de lendemain ou que je pendais FILE *s comme du linge sale. Je suppose généralement (lire: espérons désespérément) que toute la mémoire est nettoyée au moins à la fin du programme. Existe-t-il des situations où la fuite de mémoire ne sera pas collectée à la fin du programme 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 l'expression "comme s'il n'y a pas de lendemain" et "balançant ... comme du linge sale". Dangereux * malloc * ing peut blesser ceux que vous aimez. Veuillez également faire preuve de prudence avec du linge sale.

118
DilithiumMatrix

Non. Les systèmes d'exploitation libèrent toutes les ressources détenues par les processus à leur sortie.

Cela s'applique à toutes les ressources du 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 prendre du temps pour libérer certaines ressources. Par exemple, le port TCP qu'un serveur réseau utilise pour accepter les connexions peut prendre quelques minutes pour devenir libre, même s'il est correctement fermé par le programme. Un programme en réseau peut également contenir distant = ressources telles que les 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.

110
Joni

La norme C ne spécifie pas que la mémoire allouée par malloc est libérée à la fin du programme. Cela est fait par le système d'exploitation et tous les systèmes d'exploitation (généralement ceux du monde intégré) ne libèrent pas la mémoire à la fin du programme.

47
ouah

Comme toutes les réponses ont couvert la plupart des aspects de votre question w.r.t. OS modernes, mais historiquement, il y en a un qui mérite d'être mentionné si vous avez déjà programmé dans le monde DOS. Terminant et Stay Resident (TSR), les programmes retournaient généralement le contrôle au système mais résidaient dans la mémoire qui pouvait ê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 dans la 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 ne récupérant pas de mémoire soit parce que c'est bogué ou parce que le système d'exploitation intégré est conçu pour le faire.

Je me souviens d'un autre exemple. Customer Information Control System (CICS), un serveur de transactions qui fonctionne principalement sur les mainframes IBM est pseudo-conversationnel. Une fois exécuté, il traite les données saisies par l'utilisateur, génère un autre ensemble de données pour l'utilisateur, transfère vers le nœud de terminal d'utilisateur et se termine. Lors de l'activation de la touche d'attention, il reprend à nouveau pour traiter un autre ensemble de données. Parce que la façon dont il se comporte, techniquement à nouveau, le système d'exploitation ne récupérera pas la mémoire des programmes CICS terminés, sauf si vous recyclez le serveur de transactions CICS.

28
Abhijit

Comme les autres l'ont dit, la plupart des systèmes d'exploitation récupèrent la mémoire allouée à la fin du processus (et probablement d'autres ressources comme 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 utilisez 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 juste, 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. Ne laissez pas les choses pendre. Ne comptez pas sur le nettoyage du système d'exploitation après vous. Nettoyez-vous après vous-même.

8
Andre Kostur

Cela dépend 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.

7
john

Si le programme est jamais transformé en un composant dynamique ("plugin") qui est chargé dans l'espace d'adressage d'un autre programme, il sera gênant, même sur un système d'exploitation avec une gestion de la mémoire bien rangée. Nous n'avons même pas à penser au code porté sur des systèmes moins performants.

D'un autre côté, libérer toute la mémoire peut influer sur les performances du nettoyage d'un programme.

Un programme sur lequel je travaillais, un certain cas de test nécessitait 30 secondes ou plus pour que le programme se termine, car il se reproduisait dans 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 avec des cas de test, mais désactivez-la dans le code de production pour que l'application se ferme rapidement.

5
Kaz

Tous les systèmes d'exploitation méritant le titre nettoieront le désordre que votre processus a fait après la résiliation. Mais il y a toujours des événements imprévus, que se passe-t-il si l'accès lui est refusé d'une manière ou d'une autre et qu'un mauvais programmeur n'en prévoit pas la possibilité et qu'il ne réessaye pas un peu plus tard? Toujours plus sûr de simplement vous nettoyer SI les fuites de mémoire sont essentielles à la mission - sinon cela ne vaut pas vraiment l'effort OMI si cet effort est coûteux.

Edit: Vous devez nettoyer les fuites de mémoire si elles sont en place où elles s'accumuleront, 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 d'une autre sorte, ce sera probablement un problème grave tôt ou tard.

En termes techniques, si vos fuites sont de "complexité" de la mémoire O(1) elles sont très bien dans la plupart des cas, O(logn) déjà désagréables (et dans certains cas mortels) et O (N) + intolérable.

5
user2180519

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é.

3
klearn

Si vous avez une communication interprocessus, cela peut conduire à ce que d'autres processus ne se terminent jamais et consomment des ressources en fonction du protocole.

Pour donner un exemple, j'étais en train d'expérimenter l'impression sur une imprimante PDF dans Java lorsque j'ai mis fin à la JVM au milieu d'un travail d'impression, le = PDF le processus de mise en file d'attente est resté actif et j'ai dû le tuer dans le gestionnaire de tâches avant de pouvoir réessayer l'impression.

2
ratchet freak