Comment éviter les memory leaks lorsque l’utilisateur appuie sur ctrl + c sous linux?

Dans mon programme écrit en C et C ++, je vais créer un nouvel object pour remplir la tâche, puis supprimer l’object.

Au moment suivant le nouvel object mais avant la suppression, si l’utilisateur appuie sur ctrl + c pour interrompre le processus, la suppression ne sera pas appelée et une fuite de mémoire surviendra.

Que dois-je faire pour éviter cette situation?

De plus, si la mémoire était récupérée par le système d’exploitation, qu’en est-il des fichiers ouverts? Sont-ils fermés par le système d’exploitation ou dois-je les fermer manuellement?

Dans un système basé sur la mémoire virtuelle, toute la mémoire est renvoyée au système d’exploitation lorsqu’un processus est arrêté, qu’il ait été libéré explicitement ou non dans le code de l’application. La même chose pourrait ne pas être vrai pour d’autres ressources, que vous voudrez peut-être libérer proprement. Dans ce cas, vous devez fournir un gestionnaire de signal personnalisé pour le signal SIGINT (reçu en Ctrl + C), voir par exemple http://linux.die.net/man/2/sigaction .

Si vous appuyez sur Ctrl C , un processus SIGINT sera envoyé au processus. SIGINT -ci procédera par défaut à un arrêt pratiquement ordonné, notamment en supprimant le gestionnaire de mémoire et en libérant tous les tas et stacks alloués. Si vous devez effectuer d’autres tâches, vous devrez installer un gestionnaire SIGINT et effectuer ces tâches vous-même.

Lorsque vous appuyez sur CTRL + C dans une console Linux, le signal SIGINT est envoyé à l’application qui, si le signal n’a pas de gestionnaire, mettra fin au programme et renverra toute la mémoire au système d’exploitation. Bien entendu, cela rendrait inutile toute libération de mémoire, car toute la mémoire sera libérée une fois le programme créé. Toutefois, si vous souhaitez gérer le signal SIGINT CTRL + C (peut-être écrire certaines dernières données dans un fichier ou effectuer un autre nettoyage), vous pouvez utiliser la fonction signal() pour installer une fonction à appeler lorsque le signal est reçu. Consultez la page de manuel de cette fonction si vous souhaitez en savoir plus.

Si vous avez alloué des segments de mémoire partagée SYSV à l’aide de shmget(2) vous devez alors nettoyer vous-même avec shmctl(2) .

Si vous avez alloué des segments de mémoire partagée POSIX à l’aide de shm_open(3) vous devez alors nettoyer vous-même avec shm_unlink(3) .

Les segments de mémoire partagée SYSV et POSIX persistent après la fin du processus. Vous pouvez voir ce qui persiste en utilisant l’ ipcs(1) .

Bien entendu, si vous n’avez pas utilisé de segments de mémoire partagée SYSV ou POSIX, tout cela n’est que bruit. 🙂

Si le processus se ferme, une fuite de mémoire ne se produira normalement PAS.

La plupart de la mémoire que vous allouez sera libérée en Ctrl + C. Si vous constatez que l’utilisation de la mémoire ne revient pas à son niveau précédent, cela est probablement causé par des blocs de système de fichiers en mémoire tampon.

Cependant, vous devez absolument nettoyer les choses, en particulier si vous avez utilisé d’autres types de ressources:

  • Les fichiers créés dans des répertoires temporaires ne seront pas supprimés. Cela inclut / dev / shm, laisser un tel fichier pourrait être considéré comme une “fuite de mémoire”.
  • Les segments de mémoire partagée System V ou posix ne seront pas jetés lorsque votre processus se fermera. Si cela vous dérange, nettoyez-les spécifiquement. Sinon, nettoyez-les lors d’une exécution ultérieure.

Normalement, une fuite (d’un object persistant ou semi-persistant, par exemple un fichier) n’a pas d’importance si une exécution ultérieure ne perd pas plus de mémoire. Donc, nettoyer sur une course future est suffisant.

Imaginez un processus exécuté toutes les 5 minutes à partir de “cron”. S’il se bloque à chaque exécution et laisse des dégâts, il est toujours correct à condition que chaque exécution supprime les dégâts du précédent plantage.

Le système d’exploitation récupère la mémoire allouée par le processus lorsque celui-ci se ferme à la suite de Ctrl-C ou de tout autre moyen.

Vous vous abonnez à une idée fausse assez commune selon laquelle les blocs de segments non libérés, mais toujours accessibles au moment de la création du programme, sont des fuites. Ce n’est pas vrai. Les blocs qui fuient sont ceux qu’aucun pointeur ne mentionne encore, par conséquent, ils ne peuvent pas être libérés.

Au cours des années passées à jouer (et à casser) beaucoup de kernelx parfaitement bons, je n’ai jamais réussi à écraser suffisamment un gestionnaire de mémoire virtuelle au point qu’il ne récupérait plus tout l’espace adresse d’un processus une fois sorti. Si vous ne travaillez pas avec un kernel clairement identifié comme “nouveau et expérimental”, vous aurez plus de chance de gagner à la loterie que de trouver un système qui n’utilise pas de gestionnaire de mémoire virtuelle efficace.

Ne mettez pas votre code dans le code pour obtenir un score parfait dans Valgrind. Si vous n’avez aucune tâche de nettoyage à effectuer autre que la libération de mémoire qui contient toujours des références valides , inutile de vous en préoccuper. Si quelqu’un envoie un kill -9 à votre programme, vous ne pourrez pas le gérer et vous verrez l’ancien comportement se répéter.

Si vous avez des descripteurs de fichiers à nettoyer, des verrous partagés à abandonner, des stream à vider ou quoi que ce soit d’autre pour que d’autres processus ne vous manquent pas lorsque vous êtes parti, prenez bien soin de cela. Il suffit de ne pas append de code qui ne résout en rien le problème, cela semble ridicule de le faire.

Remarque

Cela devait être à l’origine un commentaire, mais est beaucoup trop long et craint donc beaucoup d’écrire un roman, un commentaire à la fois.