Aller au contenu

free et malloc


Messages recommandés

salut,

j'ai ce bout de code

int main()
{
contact ct={0};//declaration de structure contact
ptr_contact new_ct=malloc(sizeof(ct)); 
ct=entr();
new_ct=&ct;

ct_write(&ct);
ct_write(new_ct);

free(ct.adresse); // les free pour libérer l'espace memoire alloué
free(new_ct);
system("pause");


return 0;
}

qui me declenche un point d'arret (sous windows) à la ligne "free(new_ct);"

pourtant mon new_ct est bien alloué...^^

donc je vois pas trop d'ou vient le probleme

quoi qu'il en soit sa me conduit a me poser une question

ne serait il pas possible de coder une fonction dont le proto serait du genre

free(void)

et qui permettrait de liberer tous les espaces memoires alloués ...

l'idée etait de creer une fonction qui recuperrerait toutes les adresses des pointeur de l'appli, verifirait s'il sont ==NULL et dans le cas contraire, ferait un free des pointeur en question ??

histoire de pas avoir besoins de faire des free(qqch) a tout bout de champ

je sais pas si j'ai été très clair .... :transpi:

[EDIT]

en fait on dirait que mon malloc(sizeof(ct)) est parfaitement inutile ...

mais sa change rien a ma question

[EDIT 2] quelqu'un sait comment depalcé l'indicateur de position sur stdout ?

Lien vers le commentaire
Partager sur d’autres sites

ca se fait, j'ai deja eu des camarades de promos qui rendaient leurs projs avec une libmalloc perso

le principe : tu appelles mon_malloc() et mon_free() (appelant les fonctions de malloc)

et a cote, tu as tout une gestion des elements alloues

ton malloc, en plus d'allouer/retourner l'adresse memoire, le garde dans une liste

et tu peux alors coder des dump_allocs(), magic_free(), ...

ou sinon, tu peux recoder malloc. a defaut d'etre utile, c'est marrant :transpi:

sbrk()

et pour en revenir a ton bout de code, pas la peine de malloc new_ct

le fait de faire new_ct = &ct "alloue" ton pointeur (enfin, le fait pointer sur une vaiable statique)

tu peux faire printf("addr=%p\n", var); pour afficher l'addresse memoire de `var' (et donc, verifier que malloc n'a pas echoue)

et constater que l'addresse de ton pointeur n'est pas dans la zone memoire ou malloc va piocher

donc, effectivement, au free(), ca passe pas ^^

pour deplacer "l'indicateur de position" (le curseur ?), sous unix, t'as la lib curses, et j'ai cru comprendre qu'il y avait quelque chose d'assez proche pour windows, sans doute sous le meme nom.

sinon, a tester, mais sous nux, en general, je me contente d'ecrire sur stdout ce qu'une touche directionnelle envoit ; ca marche tout aussi bien, sans libs.

Lien vers le commentaire
Partager sur d’autres sites

ca se fait, j'ai deja eu des camarades de promos qui rendaient leurs projs avec une libmalloc perso

le principe : tu appelles mon_malloc() et mon_free() (appelant les fonctions de malloc)

et a cote, tu as tout une gestion des elements alloues

ton malloc, en plus d'allouer/retourner l'adresse memoire, le garde dans une liste

et tu peux alors coder des dump_allocs(), magic_free(), ...

ouais je vais peut etre m'en faire une, un genre de macro qui mettrai toutes les adresse dans un array global de int, et qui les trierai, puis un tri des adresse, et enfin une fonction free_global, pour liberer tous ce qui ne l'a pas été fait avant....

merci pour l'idée

ou sinon, tu peux recoder malloc. a defaut d'etre utile, c'est marrant :D

sbrk()

:transpi:

mephisto bientot barbu ?...^^

sous win les touches directionnelles affiche le caractère O (avec accent...)

Lien vers le commentaire
Partager sur d’autres sites

Quand tu fermes le programme, c'est pas l'OS qui s'occupe de désallouer les zones ?

C'est sur que tu peux le faire avant...

Pour ma part, je vois plutôt le bien fondé d'un malloc/free perso pour repérer les fuites, mais pas vraiment pour en faire un garbage collector (en C du moins. En c++ bien objet, y a moyen de gérer ça à la destruction d'une instance)

Lien vers le commentaire
Partager sur d’autres sites

Quand tu fermes le programme, c'est pas l'OS qui s'occupe de désallouer les zones ?

normalement oui, mais comme ont dit, ont est jamais mieux servi que part sois meme...

par contre en ce qui concerne les malloc un peut plus securisés, j'avais trouvé ça :

http://fplanque.net/Blog/devblog/1995/07/0...uer_les_mallocs

dommage que les fichier .c/.h soit à remettre en ordre soit meme...

Lien vers le commentaire
Partager sur d’autres sites

sous win les touches directionnelles affiche le caractère O (avec accent...)
fais un read, printf ton buffer (les valeurs ASCII), il y a tres certainement un code different pour chaque touche

ca marcherait moins bien autrement :)

Comment tu sauras si ta zone mémoire n'est plus utile dans le prog ?
ce n'est pas une question d'utilite, mais de coherence

Le kernel prépare au moins trois zones pour un process (userland) :

- Une zone de texte pour le code éxécutable (normalement RO)

- Une zone de data pour les données statiques et données dynamiques

- Une zone de stack pour les variables locales et les paramètres des fonctions

Test sur ta machine pour t'en faire une idée

Mais avec un printf d'addresses, tu vois tout de suite s'il s'agit d'une variable locale, ou d'une variable qui spawné via sbrk/malloc

Quand tu fermes le programme, c'est pas l'OS qui s'occupe de désallouer les zones ?
Si, le kernel va (normalement, apres, tu peux recoder...) zapper les allocations d'un process a sa fermeture.

C'est pas une raison pour etre un gros porc.

Et oui, les garbages collector, c'est sympa, mais c'est une autre philosophie, un autre code, ... Quand tu prends la decision de faire ton appli en C et pas en Java, en C++, .... il y a une raison :)

Lien vers le commentaire
Partager sur d’autres sites

Je suis d'accord avec tout ça :transpi:

Ma question était justement de m'éclaircir sur l'utilité d'un malloc/free perso.

Pour du monitoring/debugging je trouve ça très bien de surveillez les allocations dynamiques. Il y a toujours des trucs qui peuvent trainer inutilement.

Mais dans le cadre d'une libération de mémoire automatique, je vois pas trop comment faire...

Lien vers le commentaire
Partager sur d’autres sites

faust@alpha ~ : cat toto.c																															   10:52

#include		<errno.h>
#include		<stdlib.h>
#include		<stdio.h>
#include		<string.h>

struct				  s_alloc
{
void				*ptr;
struct s_alloc	  *next;
};

struct s_alloc		  *add_elt(struct s_alloc *elt, unsigned int u)
{
struct s_alloc	  *nw, *mv;

u += sizeof(struct s_alloc);
if ((nw = malloc(u)) == NULL)
{
	fprintf(stderr, "can not allocate more %u bytes\n", u);
	exit(ENOMEM);
}
memset(nw, 0, u);
nw->ptr = (void*)nw + sizeof(struct s_alloc);
nw->next = NULL;

for (mv = elt; mv && mv->next != NULL; mv = mv->next);
if (elt)
	mv->next = nw;
else
	elt = nw;

return elt;
}

void					dump_elts(struct s_alloc *elt)
{
struct s_alloc	  *mv;

fprintf(stdout, "dumping memory:\n");
for (mv = elt; mv && mv->next != NULL; mv = mv->next)
	fprintf(stdout, "	got [%p]\n", mv->ptr);
if (mv)
	fprintf(stdout, "	got [%p]\n", mv->ptr);
fflush(stdout);
}

void					magic_free(struct s_alloc *elt)
{
struct s_alloc	  *mv, *last;

for (mv = elt, last = NULL; mv && mv->next != NULL; last = mv, mv = mv->next)
	if (last)
		free(last);
if (last)
	free(last);
}

int					 main(void)
{
struct s_alloc	  *mem = NULL;
int				 loop;

for (loop = 0; loop < 100000; loop++)
{
	mem = add_elt(mem, 32);
//	  dump_elts(mem);
	mem = add_elt(mem, 16);
//	  dump_elts(mem);
	mem = add_elt(mem, 128);
//	  dump_elts(mem);
	mem = add_elt(mem, 12);
//	  dump_elts(mem);
	magic_free(mem);
	mem = NULL;
}

return 0;
}
faust@alpha ~ : cat tata.c																															   10:52

#include		<errno.h>
#include		<stdlib.h>
#include		<stdio.h>
#include		<string.h>

void					*mymalloc(unsigned int u)
{
void				*nw;

if ((nw = malloc(u)) == NULL)
{
	fprintf(stderr, "can not allocate more %u bytes\n", u);
	exit(ENOMEM);
}
memset(nw, 0, u);

return nw;
}

int					 main(void)
{
void				*ptr = NULL;
int				 loop;

for (loop = 0; loop < 100000; loop++)
{
	ptr = mymalloc(sizeof(ptr) * 32);
	free(ptr);
	ptr = mymalloc(sizeof(ptr) * 16);
	free(ptr);
	ptr = mymalloc(sizeof(ptr) * 128);
	free(ptr);
	ptr = mymalloc(sizeof(ptr) * 12);
	free(ptr);
}

return 0;
}
faust@alpha ~ : time ./tata																															  10:53
0.029u 0.000s 0:00.03 66.6%	 0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./toto																															  10:53
0.019u 0.003s 0:00.02 50.0%	 0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./tata																															  10:53
0.033u 0.000s 0:00.03 100.0%	0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./toto																															  10:53
0.019u 0.003s 0:00.02 50.0%	 0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./tata																															  10:53
0.029u 0.000s 0:00.03 66.6%	 0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./toto																															  10:53
0.019u 0.003s 0:00.02 50.0%	 0+0k 0+0io 0pf+0w
faust@alpha ~ : time ./tata																															  10:53
0.029u 0.000s 0:00.03 66.6%	 0+0k 0+0io 0pf+0w

un exemple de libération automatique (toto.c)

et pour le trip, un "équivalent" sans libération (tata.c)

tu perds sizeof(struct s_alloc) sur chaque allocation, c'est pas forcément le plus propre

mais ça reste raisonnable (pas une grosse saloperie, et au final, sur ce petit exemple, c'est même plus rapide)

après, on peut faire plus/moins propre/fonctionnel, avec un s_alloc en global, en retournant l'adresse "effective" (*s_alloc + sizeof(s_alloc)), ... c'est juste une interprétation

et, en effet, en dehors du cadre du débug/mise au propre, ça n'a pas vraiment d'utilité

ou faut vraiment avoir une bonne raison (tu veux faire ta merde, tu penses pouvoir faire mieux/plus rapide, ... tu es gay, ..., tu veux recod tout malloc parceque tu n'aimes pas l'esthétique de son mapping, ...)

Lien vers le commentaire
Partager sur d’autres sites

Moi j'ai recodé malloc pour que ça affiche des smileys en ASCII art dans les dumps mémoire quand je débug.

en fait ce qu'il faudrait c'est reussir a coder un malloc qui empeche la lecture/ecriture au-dela de sont indice maximum, mais la je pense que sa doit se gerer au niveau de l'OS

Lien vers le commentaire
Partager sur d’autres sites

  • 3 mois après...
Moi j'ai recodé malloc pour que ça affiche des smileys en ASCII art dans les dumps mémoire quand je débug.

en fait ce qu'il faudrait c'est reussir a coder un malloc qui empeche la lecture/ecriture au-dela de sont indice maximum, mais la je pense que sa doit se gerer au niveau de l'OS

Possible au niveau du langage, mais perte de performances, pourquoi donc avoir choisi C ?

Ces fonctions qui "posent problème" ne vérifient rien, donc aucune étape intermédiaire entre le moment où vous demandez l'écriture et l'écriture elle même des données. (quoique j'exagère un peu...)

Lien vers le commentaire
Partager sur d’autres sites

salut,

j'ai ce bout de code

int main()
{
contact ct={0};//declaration de structure contact
ptr_contact new_ct=malloc(sizeof(ct)); 
ct=entr();
new_ct=&ct;

ct_write(&ct);
ct_write(new_ct);

free(ct.adresse); // les free pour libérer l'espace memoire alloué
free(new_ct);
system("pause");


return 0;
}

qui me declenche un point d'arret (sous windows) à la ligne "free(new_ct);"

pourtant mon new_ct est bien alloué...^^

donc je vois pas trop d'ou vient le probleme

Regardons un peu ton code :

1° tu déclares une structure contacte du nom de ct

2° tu déclare un pointeur vers un structure contact qui s'appelle new_ct et tu lui alloue l'espace d'un contact

3° tu copies dans ct le contact fourni en retour de entr(), là, j'imagine que la fonction entr() alloue une nouveau contact et le renvoie en valeur de retour. Il y a donc un nouveau contact alloué sur le tas

4° tu fais pointé new_ct vers l'adresse de ct. BAM!, l'espace alloué avec malloc est perdu... Il est alloué, mais tu n'a plus aucun pointeur qui pointe vers lui, donc tu ne pourras jamais faire de free dessus

5° quelques write

6° tu libères le contact alloué par entr(), grâce à la copie de son adresse stocké dans ct. Du coup, new_ct pointe vers le néant absolu. Note bien que ct contient toujours toutes les valeurs du contact dont il est la copie, c'est juste que l'original a été libéré.

7° tu essaye de libérer new_ct, et BAM, une erreur au runtime, puise que l'espace mémoire vers lequel il pointait a été libéré...

Bref, pas besoin de refaire malloc et free, suffit d'utiliser un débuggeur.

Si tu ne veux pas te faire chier avec la gestion de la mémoire, prend un langage managé, fait du java, du D ou du C#...

:yes:

Lien vers le commentaire
Partager sur d’autres sites

salut,

j'ai ce bout de code

int main()
{
contact ct={0};//declaration de structure contact
ptr_contact new_ct=malloc(sizeof(ct)); 
ct=entr();
new_ct=&ct;

ct_write(&ct);
ct_write(new_ct);

free(ct.adresse); // les free pour libérer l'espace memoire alloué
free(new_ct);
system("pause");


return 0;
}

qui me declenche un point d'arret (sous windows) à la ligne "free(new_ct);"

pourtant mon new_ct est bien alloué...^^

C'est juste que new_ct n'a pas à être allooué avec malloc, ni libéré avec free.

int main()
{
contact ct={0};//declaration de structure contact 
                 // non ce n'est pas une déclaration. C'est la definition et l'initialisaion d'une 
                 // structure contact dans la mémoire locale (la pile).

ptr_contact new_ct=malloc(sizeof(ct)); 
                // reservation de la place suffisante dans le tas pour un second objet contact 
                // et stockage du pointeur vers cette espace dans new_ct
ct=entr();
                // copie dans l'objet ct de ce que entr a renvoyé. (ce qui montre que l'initialisation ={0} était inutile).
new_ct=&ct;
                // effacement de l'ancienne valeur de new_ct, et en conséquence perte definitive 
                // de la mémoire allouée (inutilement) par malloc

ct_write(&ct);
                // applique la fonction ct write à l'objet ct via le pointeur sur celui ci
ct_write(new_ct); // exactement equivalent à ct_write(&ct), sauf si il y a deux ct_write:
                // ct_write(contact const *&) et ct_write(contact *&) (ce dont je doutes fort) ou si c'est une macro.

                // applique la fonction ct write à l'objet ct via le pointeur sur celui ci
                // new_ct est ici parfaitement inutile. 

free(ct.adresse); // les free pour libérer l'espace memoire alloué
                // commentaire inutile: free est clairement la fonction chargée de libérer la mémoire allouée.
                // un commentaire utile serait de dire qui a alloué ce ct.adresse ?
                // habituellement on ne fait pas allouer de la mémoire par une sous fonction, ici probablement entr()
                // pour la faire libérer par son appelant
free(new_ct);
                // libération erronée d'un objet sur la pile (ct). ca va planter.
system("pause");


return 0;
}

Par ailleurs tu fais du c++ , (utilisation de // ) donc malloc et free ne sont pas indiqués, et la gestion de ct.adresse se fait par un destructeur, elle n'est pas laissée au bon vouloir des utilisateurs de "contact".

sinon le sujet de quand et comment on désalloue est un vaste sujet... et la première réponse est "surtout pas au petit bonheur la chance".

Une autre réponse est:

on désalloue quand on n'a plus besoin de la chose...

Reste à savoir quand ca arrive. C'est par ce que la réponse à cette question est un peu compliquée que la gestion de la mémoire est délicate en C et en C++. En C# et en java, c'est géré automatiquement. Malheureusement pour les ceux qui utilisent ces deux derniers langages propriétaires, on montre facilement qu'il n'existe pas de stratégie optimale pour libérer automatiquement juste au bon moment la mémoire. Le résultat net c'est que ton super logiciel de traitement d'image en C# par exemple, va "oublier" de libérer les 16Go de ram qu'il a réservé pour traiter la grosse image que viens juste de fermer... et tu auras raison de traiter l'auteur de ce soft de plouc idiot, au prix de la ram... En c et c++, quand c'est bien fait, généralement c'est le contraire qui arrive (elle est libérée juste à temps).

Mais bon... tu veux savoir. la réponse est: il y a plusieurs techniques. et plusieurs questions:

La réponse générale est : "ont peut libérer la mémoire quand personne n'en a plus besoin". Si on réfléchit ca veut dire que ca dépend du programme tout entier... y compris les parties non encore écrites. S'il y a des DLL ou si le programme communique avec l'extérieur (ce qui est assez commun), peut être même qu'on ne peut pas répondre quand on livre son programme... Donc potentiellement on ne peut jamais répondre (ce qui démontre ce que je disais au dessus: il n'existe pas de stratégie optimale générale).

On peut (sur) simplifier en disant: si personne ne possède de pointeur sur une zone mémoire... elle est devenue inutile. Pourquoi "sur"simplifier? Qu'est ce qui m'empêche de m'envoyer l'adresse en hexa par email, puis de la décoder à la reception? Pourquoi je ne pourrais pas scanner toute la mémoire du processus à la recherche de ma donnée dont je n'ai pas l'adresse? Vous trouvez ca idiot? Vous avez tort, je l'ai vu faire (et même une fois à juste raison).

Et puis d'abord? Est-ce que une adresse au milieu d'une zone indique que la zone est utilisable? Peut être bien..

Sur-simplifions encore: Considérons que une zone qui n'a pas de pointeur sur son début est devenue inutile. La question est: comment on le sait?

La première technique, très simple et très efficace de gestion automatique de la mémoire est tirée de cette question: supposons que nous ajoutions à côté de la zone mémoire (par exemple juste au début) un compteur du nombre de pointeurs qui pointent dessus.

Chaque fois qu'un nouveau pointeur pointe dessus, on augmente le compteur, et chaque fois qu'un pointeur s'apprète à ne plus pointer dessus on décrémente. Si le compteur tombe à 0 : on libère la mémoire.

cela semble être la méthode idéale... n'est ce pas? On l'appelle "compteur de référence"

malheureusement il y a un problème... saurez vous le trouver?

...

...

...

Bon, je vous le dis:

si l'objet A contient un pointeur sur B et que B contient un pointeur sur A, alors on peut perdre le contact avec A et B sans que leurs compteurs tombent à 0.

J'entends dans le fond de la classe qu'il y en a qui dorment...

Pour compenser ce problème il faut se rendre à l'évidence: il va falloir chercher quels sont les objets qu'on ne peut atteindre par aucun chemin.... et ca peut couter cher en temps de calcul.

Les algos qui font ca s'appellent des ramasse-miettes. c'est ca qu'on utilise en c# et en java.

Si seulement les #@@|^$ qui gèrent le C++ s'étaient donnés la peine de rendre le C++ réflexif (il suffirait de savoir ou sont les objets d'un type donné dans une structure) et on saurait aussi le faire efficacement en C++. On aurait alors un C++ qui ferait tout ce que fait le C#, mais qui ferait aussi tout ce que le C# ne peut pas faire. On ferait du ramasse miette l ou c'est la bonne solution, et de la gestion explicite quand c'est nécessaire. Mais non, Stroustrup a déjeuné de travers et ca ne passe pas.

Lien vers le commentaire
Partager sur d’autres sites

Qu'est ce qui m'empêche de m'envoyer l'adresse par email, puis de la décoder à la reception?

La mémoire virtuelle, peut-être...

:roll:

heuuhh en fait... rien. on peut le faire. La mémoire virtuelle du point de vue de programme c'est de la mémoire normale. c'est juste que l'OS joue à Madoff avec cette mémoire: il promet qu'il y a de la mémoire à cet endroit... et il n'y en a pas forcement, il l'a refilé à quelqu'un. Quand on essaie d'y acceder, il vous endort comme un véto endort un éléphant, tapisse de la mémoire là ou vous en vouliez et vous injecte l'antidote au sommnifère.

Lien vers le commentaire
Partager sur d’autres sites

Nah, pas vraiment. La mémoire virtuelle consiste à dissocier l'espace d'adressage physique (les barettes présente dans l'ordi) de l'espace d'adressage du processus (les adresses que tu manipules quand tu codes). À partir de là, l'adresse que tu vois quand tu fait printf d'un pointeur, ne correspond en rien à une adresse physique. Le seul moyen de faire cette correspondance, c'est de connaître les tables de correspondance du mécanisme de pagination et de celui de segmentation. Ces tables, il n'y a que le noyau qui y a accès, et il ne les mélange pas entre les processus. En plus, il ne le fait pas lui même, il utilise un circuit matériel pour le faire (la MMU).

Conclusion, si tu veux faire un programme userland qui lit une adresse mémoire donnée par un autre processus et qui retrouve la variable correspondante, bon courage, c'est juste pas possible.

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...