C'est quelque chose qui me dérange depuis longtemps.
On nous a tous appris à l'école (du moins, moi) que vous DEVEZ libérer chaque pointeur alloué. Je suis un peu curieux, cependant, de connaître le coût réel de la non-libération de la mémoire. Dans certains cas évidents, comme lorsque malloc
est appelé à l'intérieur d'une boucle ou d'une partie de l'exécution d'un thread, il est très important de le libérer pour éviter les fuites de mémoire. Mais considérez les deux exemples suivants :
D'abord, si j'ai un code qui est quelque chose comme ça :
int main()
{
char *a = malloc(1024);
/* Do some arbitrary stuff with 'a' (no alloc functions) */
return 0;
}
Quel est le véritable résultat ici ? Je pense que le processus meurt et que l'espace du tas a disparu de toute façon, donc il n'y a pas de mal à manquer l'appel à free
(cependant, je reconnais l'importance de l'avoir quand même pour la fermeture, la maintenabilité et les bonnes pratiques). Ai-je raison de penser ainsi ?
Deuxièmement, disons que j'ai un programme qui agit un peu comme un shell. Les utilisateurs peuvent déclarer des variables comme aaa = 123
et ceux-ci sont stockés dans une structure de données dynamique pour une utilisation ultérieure. Il semble évident que vous utiliserez une solution qui fera appel à une fonction *alloc (hashmap, liste liée, quelque chose comme ça). Pour ce type de programme, cela n'a pas de sens de ne jamais libérer après l'appel de la fonction malloc
parce que ces variables doivent être présentes à tout moment pendant l'exécution du programme et qu'il n'y a pas de bon moyen (à ma connaissance) d'implémenter cela avec de l'espace alloué statiquement. Est-ce que c'est une mauvaise conception d'avoir un tas de mémoire qui est allouée mais seulement libérée dans le cadre de la fin du processus ? Si oui, quelle est l'alternative ?
8 votes
@NTDLS La magie du système d'évaluation fonctionne pour une fois : 6 ans plus tard, la réponse "plus méritante" a effectivement atteint le sommet.
22 votes
Les personnes ci-dessous ne cessent de dire qu'un bon système d'exploitation moderne fait le nettoyage, mais que se passe-t-il si le code s'exécute en mode noyau (par exemple, pour des raisons de performances) ? Les programmes en mode noyau (dans Linux par exemple) sont-ils sandboxés ? Si ce n'est pas le cas, je crois qu'il faudrait alors tout libérer manuellement, je suppose, même avant toute terminaison anormale comme avec abort().
6 votes
@Dr.PersonPersonII Oui, le code s'exécutant en mode noyau doit généralement tout libérer manuellement.
2 votes
Je voudrais ajouter que
free(a)
ne fait pas vraiment quelque chose pour libérer de la mémoire ! Il réinitialise simplement certains pointeurs dans l'implémentation libc de malloc qui gardent la trace des morceaux de mémoire disponibles à l'intérieur d'une grande page de mémoire mappée (communément appelée le "tas"). Cette page ne sera toujours libérée que lorsque votre programme se terminera, pas avant.0 votes
@MarcoBonelli Partiellement vrai. Si le
malloc()
ed provenait du tas "normal" de sbrk, et était à sa fin,sbrk()
est appelé pour réduire l'image mémoire. Et simalloc()
a alloué la mémoire viammap()
il est non cartographié dansfree()
.0 votes
@glglgl Vrai ! Code source pertinent . Et oui.
malloc()
peut renvoyer des pages dédiées complètes pour de très gros morceaux. La valeur seuil par défaut semble être 128k, mais bien sûr cela dépend de la configuration ( source ).0 votes
@MarcoBonelli Mais dans le même code il est clairement visible que
free()
ne se contente pas de réinitialiser certains pointeurs (comme vous le prétendez), mais fait beaucoup d'autres choses, y compris l'appel àsystrim()
.0 votes
Dans votre programme utilisateur moyen, free ne fait rien d'extraordinaire, il déplace simplement les pointeurs pour réorganiser l'arène principale lorsque des morceaux sont libérés. Ces situations où munmap, sbrk, etc. sont appelés ne sont pas si courantes. C'est ce que je disais.
1 votes
Free() peut, ou non, libérer la mémoire. Elle peut simplement marquer le bloc comme étant libéré, pour être récupéré plus tard, ou peut le lier à une liste libre. Elle peut le fusionner avec des blocs libres adjacents, ou laisser cette tâche à une allocation ultérieure. Tout ceci est un détail d'implémentation.
0 votes
@SOStinks Un "programme" du noyau ne se termine pas comme un programme en espace utilisateur. L'équivalent de l'"existence" du code du noyau est l'arrêt du système, auquel cas vous n'avez pas besoin de le libérer. C'est juste que dans le noyau, vous êtes typiquement en train de tourner pendant si longtemps qu'il y a très peu de cas où vous avez besoin de le libérer. Ne le fais pas. besoin de libérer de la mémoire.