[C/Unix] Problème de copie à l'écriture avec fork()
Le
JKB
Bonjour à tous,
Je butte sur un problème qui doit être idiot. J'ai un programme
écrit en C sous Unix qui a une fuite de mémoire assez conséquente
lors d'un fork (ça peut faire quelques Mo).
Considérons une processus père qui effectue une boucle. Dans cette
boucle, il fait un fork() et continue ses traitements dans lesquels
il y a des allocations de gros blocs de mémoire.
Le fils est fichu de voir ces allocations alors qu'elles ont lieu
_après_ le fork().
Grossièrement, l'algorithme est le suivant :
while(1)
{
ios = fork();
if (ios = 0)
{
// plein de trucs tordus
exit(0);
}
else
{
// sleep();
mem = malloc();
// plein de trucs abscons
free(mem);
}
}
et je récupère le pointeur mem dans le processus fils ! Je ne vois
qu'une seule explication, le fork() en question est une copie à
l'écriture pour le fils et se fait entre le malloc() et le free().
Ou alors, le free() est reporté à plus tard et s'exécute en tâche de
fond lors de l'appel à fork(). Il faut noter que je ne
récupère ce pointeur qu'après quelques itérations. Je suis incapable
de le recevoir lors de la première, mais je ne sais pas si c'est
significatif.
Le père n'a _aucune_ fuite de mémoire (testé dans tous les sens avec
valgrind et des outils fait maison). La fuite n'apparaît que dans
les fils.
Si je rajoute un sleep() pour bloquer le père durant quelques
dixièmes de secondes, la fuite de mémoire disparaît dans les fils.
Il y a un thread parallèle au père mais il ne fait strictement
aucune allocation et j'ai testé avec hellgrind qui ne m'a trouvé
aucune race condition.
Est-ce que l'un d'entre vous aurait une idée pour forcer la copie
dès le fork() et éliminer ce problème ? Je ne suis pas sûr que ça
vienne de là, mais je préfère ôter ce doute avant de chercher
ailleurs.
Cordialement,
JKB
--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
=> http://grincheux.de-charybde-en-scylla.fr
Je butte sur un problème qui doit être idiot. J'ai un programme
écrit en C sous Unix qui a une fuite de mémoire assez conséquente
lors d'un fork (ça peut faire quelques Mo).
Considérons une processus père qui effectue une boucle. Dans cette
boucle, il fait un fork() et continue ses traitements dans lesquels
il y a des allocations de gros blocs de mémoire.
Le fils est fichu de voir ces allocations alors qu'elles ont lieu
_après_ le fork().
Grossièrement, l'algorithme est le suivant :
while(1)
{
ios = fork();
if (ios = 0)
{
// plein de trucs tordus
exit(0);
}
else
{
// sleep();
mem = malloc();
// plein de trucs abscons
free(mem);
}
}
et je récupère le pointeur mem dans le processus fils ! Je ne vois
qu'une seule explication, le fork() en question est une copie à
l'écriture pour le fils et se fait entre le malloc() et le free().
Ou alors, le free() est reporté à plus tard et s'exécute en tâche de
fond lors de l'appel à fork(). Il faut noter que je ne
récupère ce pointeur qu'après quelques itérations. Je suis incapable
de le recevoir lors de la première, mais je ne sais pas si c'est
significatif.
Le père n'a _aucune_ fuite de mémoire (testé dans tous les sens avec
valgrind et des outils fait maison). La fuite n'apparaît que dans
les fils.
Si je rajoute un sleep() pour bloquer le père durant quelques
dixièmes de secondes, la fuite de mémoire disparaît dans les fils.
Il y a un thread parallèle au père mais il ne fait strictement
aucune allocation et j'ai testé avec hellgrind qui ne m'a trouvé
aucune race condition.
Est-ce que l'un d'entre vous aurait une idée pour forcer la copie
dès le fork() et éliminer ce problème ? Je ne suis pas sûr que ça
vienne de là, mais je préfère ôter ce doute avant de chercher
ailleurs.
Cordialement,
JKB
--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
=> http://grincheux.de-charybde-en-scylla.fr

Poser une question


^
Bon, je sais que c'est un exemple, mais j'espere que tu n'as pas la meme
faute stupide dans le programme lui-meme...
Re: [C/Unix] Problème de copie à l'écriture avec fork(),
Marc Espie ?crivait dans fr.comp.lang.c :
Non, c'est un simple exemple que je n'ai même pas compilé parce que
le programme en lui-même est _beaucoup_ plus long.
JKB
--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
=> http://grincheux.de-charybde-en-scylla.fr
Et ça dure combien de temps ?
free est asynchrone en général. Est-ce que ça ne vient pas
simplement du fait que chaque fils ne vis pas assez longtemps pour
que l'OS décide de libérer vraiment la mémoire ?
Que veux-tu dire ? Il est normal, dès la deuxième itération de
la boucle, que les fils voient mem != NULL.
Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?a...amp;id_mot0
Re: [C/Unix] Problème de copie à l'écriture avec fork(),
Marc Boyer ?crivait dans fr.comp.lang.c :
Je ne saisis pas la question.
Si je colle un sleep dans le fils, le résultat est identique.
Abus de langage : je récupère un pointeur valide (sur lequel je peux
faire un free() sans que valgrind ne râle).
JKB
--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
=> http://grincheux.de-charybde-en-scylla.fr
Il semble que mem soit déclaré en dehors de la boucle while : il est donc
normal que le second fork et ses suivants voient dans mem une valeur qui a
pointé à une époque sur un bloc alloué et qui ne devrait plus l'être.
Par contre je ne comprends pas qu'il y ait une fuite mémoire dans ce cas,
puisque les deux processus devraient travailler dans des zones mémoires
différentes.
Ceci étant dit, le man de fork sous linux dit qu'il travaille en copy on
write : je ne suis pas très sûr de ce que ça implique mais il se pourrait
bien que mem ne soit pas véritablement dupliqué.... Dans cette même doc, il
est écrit que fork est en fait réalisé à partir de clone, qui sert
normalement à faire du multiflots, pour lequel l'espace est partagé.
Donc ce que vous constatez est peut-être "normal" au vu de l'implémentation.
Compte tenu des allocations/desallocations, essayez de déclarer mem dans le
bloc else du processus parent, ou forcez le à NULL après la désallocation.
Essayez aussi éventuellement de forcer mem à NULL (voire n'importe quoi)
dans le processus fils : si j'ai bien compris le concept de copy-on-write,
les fuites devraient disparaître.
Précisez éventuellement la plateforme sur la laquelle vous travaillez.
Cordialement.
--
Dominique MICOLLET
Adresse email : enlever deux francs