260 likes | 464 Views
Mémoire dynamique Allocation. Structure de la mémoire. La mémoire est une quantité de mots organisée en tableau monodimensionnel, adressables par un entier (l’adresse) Le mot-mémoire (souvent 32 bits) a une adresse physique
E N D
Structure de la mémoire • La mémoire est une quantité de mots organisée en tableau monodimensionnel, adressables par un entier (l’adresse) • Le mot-mémoire (souvent 32 bits) a une adresse physique • Il peut être subdivisé en quantités (en C: 8 bits, le char) logiquement adressables séparément (au coût de la manipulation du mot entier). 0 Taille_max Atome logiquement adressable Mot mémoire (atome physiquement adressable)
Structure des adresses (C & autres) • En ANSI-C, l’atome adressable est le char (8 bits). Raisons historiques. • C’est le seul objet dont la taille soit spécifiée dans la norme: on peut compter dessus pour la portabilité. • L’opérateur sizeof rend le nombre de chars (octets) 11 3 7 10 2 6 Mémoire 32 bits 01 1 5 00 0 4 • Toute manipulation d’adresse implique pour l’ordinateur: • Une division par quatre (cas de mots de 32 bits); troncature en fait • La recherche du mot • La recherche de l’octet dans le mot • Donc tout est plus facile/rapide quand les adresses sont des multiples de 4 (ou 8 si 64 bits, etc…) 000000 000100 001000 Adresses physiques en noir
Gestion de la mémoire Adresse Max • Dans la gestion « statique », la mémoire est utilisée par le compilateur • pour allouer les variables déclarées • intToto; • Pour passer des informations aux sous-programmes • fonc(x,y); • Et elle est gérée en pile (langages récursifs) libre Autres infos Adresse retour y x Toto utilisé Adresse 0
Les variables déclarées ont une taille fixe (scalaires) • int toto; /* 32 bits • en général: int doit être de la taille la plus rapide à manipuler. Donc 64 bits à l’occasion. Ou 16. • char cc ; /* 8 bits • C’est dans la norme • La norme dit: • sizeof(char) <=sizeof(short) <= sizeof(int) <= sizeof(long) • noter le = de <= • Pareil avec les flottants
Les variables déclarées ont une taille fixe (composées) • inttabl[100] ; • 100 x 32 bits (en général) • struct { int i1; long i2} ; • probablement 3 x 32 bits • struct {char a; short i; char b;} • Selon les optimisations et capacités du processeur: 3 x 32 bits ou 1 x 32 bits vitesse place
Il est souvent nécessaire de tailler les variables pendant l’exécution • Tableaux dont la taille n’est pas connue • Ou on taille trop grand => gaspillage • Ou on taille « au mieux » => plantages si débordements • Structures de données dynamiques • Listes, arbres, etc. int tableau[100] ; … scanf("%d " ,&nombre); for (i=0;i<nombre;i++) scanf("%d " , &tableau[i]); /* Boum si nombre >=100 */ int tableau[10000] ; /* Gaspillage */ … scanf("%d " ,&nombre); for (i=0;i<nombre;i++) scanf("%d " , &tableau[i]);
Gestion dynamique de la mémoire (1) Adresse Max 12897552 100 12897452 libre • On peut « demander » la réservation d’un bloc mémoire • char * p; /* variable déclarée, taille connue = 32 bits */ • p = (char *) malloc (100); • Ce bloc est « réservé »; il ne sera pas alloué tant qu’il ne sera pas libéré. Il n’est accessible que par son adresse (pas de nom) p 12897452 utilisé Adresse 0
Gestion dynamique de la mémoire (2) Adresse Max 12897552 100 malloc(100) 12897452 • malloc (100) • Réserve 100 octets dans la mémoire adressable • Rend un pointeur de type void * (inutilisable sous ce type) • Il faut le caster dans le type cible: • p = (char*) malloc(100) ; libre p 12897452 utilisé Adresse 0
Attention! • malloc est dans stdlib.h • malloc demande en argument le nombre de chars (octets) • Et pas le nombre de bits • Ni le nombre d’objets qu’on veut mettre dedans. • Utiliser sizeof pour convertir la taille de l’objet en nombre d’octets. • malloc rend un void * : toujours caster avant d’utiliser. • Si l’allocation est impossible: rend NULL
Libération de la mémoire Adresse Max • free(p) • Accepte n’importe quel type pointeur • Marque la mémoire concernée comme à nouveau libre • Ceci implique que le système maintient une carte de la mémoire • Aucune vérification si p ne vise pas une mémoire précédemment allouée : boum! • p ne change pas. Sa valeur ne signifie plus rien. 12897552 100 12897452 libre p 12897452 utilisé Adresse 0
Attention! free est dans <stdlib.h> free prend n’importe quel pointeur en argument • Ne le modifie pas! • Le pointeur continue à porter sa valeur qui pointe ensuite vers une mémoire non réservée. • Ne vérifie rien! En particulier • si le pointeur n’a pas été alloué, • ou déjà désalloué, • ou si c’est l’adresse d’une variable déclarée, • ou un pointeur calculé. • Donc: Il faut que la valeur donnée à free ait été antérieurement fournie par malloc, et pas encore libérée. BOUM BOUM BOUM BOUM
Équivalences pointeur/tableaux • Rappels • T équivalent à &(T[0]) • T[0] équivalent à *T • T[i] équivalent à *(T+i) • toutes substitutions possibles, donc équivalent à *(&(T[0]) +i), *(&((&(T[0]))[0]) +i), etc …
Arithmétique entre pointeurs • Rappels • Le + entre pointeur et entier signifie + (taille de l’objet pointé x entier). • (p + 3) pointe vers (p + 3 fois la taille des objets pointés par p). • (p1 – p2) rend la différence des adresses / la taille des objets pointés. • On peut toujours ramener une expression « tableau » à une expression « pointeur » et inversement.
Notation • Rappel (* p) . champ Strictement équivalent à p->champ • Pour utiliser, p doit être un pointeur vers une structure
Allocation: stratégie Mémoire Mots de 32 bits 0
Organisation Adresse du bloc N N mots alloués La taille est dans le mot qui précède l’adresse du bloc! Bloc alloué Un mot pour la taille du bloc. Bloc libre N @ Un mot pour la taille du bloc. Un mot pour l’adresse du bloc libre suivant, ou 0 s’il n’y a pas. 0 Taille Dispo Mémoire initiale: tout libre
Première allocation – p=(…)malloc(1000) 0 Taille - 4 Mémoire initiale: tout libre – un mot p FreeList 1000 1000 octets Taille - 1008 0
Deuxième allocation – q=(…)malloc(500) p FreeList 1000 1000 octets Taille - 1008 0 p q FreeList 1000 1000 octets 500 500 octets Taille - 1512 0
Troisième allocation – r=(…)malloc(300) p r q FreeList 1000 1000 octets 500 500 octets 300 300 octets Taille - 1816 0 On veut libérer q!
free (q) p r q FreeList 1000 1000 octets 500 500 octets 300 300 octets Taille - 1816 0 p r FreeList Adresse 1000 1000 octets 500 300 300 octets Taille - 1816 0
allocation – s=(…)malloc(500) p r FreeList Adresse 1000 1000 octets 500 300 300 octets Taille - 1816 0 p r s FreeList 1000 1000 octets 500 500 octets 300 300 octets Taille - 1816 0
allocation – s=(…)malloc(400) p r FreeList Adresse 1000 octets 500 300 300 octets Taille - 1816 0 1000 p s r FreeList Adresse 1000 octets 400 96 300 300 octets Taille - 1816 0 1000
allocation – s=(…)malloc(600) p r FreeList Adresse 1000 octets 500 300 300 octets Taille - 1816 0 1000 p r FreeList s Adresse 0 1000 octets 500 300 300 octets 600 0 600 octets Taille - 2420 1000
Problèmes divers • Mitage de la mémoire • Allouer « juste assez » conduit à faire des blocs libres de plus en plus petits • Stratégies diverses • Plusieurs FreeLists (par ordre de grandeur de taille des blocs alloués) • Arrondir quand le bloc restant est trop petit • Etc.
Problèmes divers • Contiguïté Adresse Adresse 500 300 Zone libre contiguë mais pas vue • D’où le ramasse-miettes (GarbageCollector) • Ou autres stratégies (insertion triée)