171 | | 1. L'allocateur d'objets (nommés blocs dans le rappel de cours au-dessus) pour l'application utilise une politique ''first fit''. Qu'est-ce que cela signifie ? Quels sont les autres ? Existe-t-il une politique meilleure que les autres et pour quel critère ? |
172 | | {{{#!protected ------------------------------------------------------------------ |
173 | | ''' |
174 | | * L'allocation ''first fit'' signifie que l'allocateur utilise le premier bloc libre assez grand pour l'objet alloué. Ce bloc libre est coupé en deux s'il est trop grand pour produire un nouveau bloc libre, mais plus petit parce qu’amputé de la partie allouée à l'objet. |
175 | | * On a aussi l'allocation ''next fit'' qui consiste à ne pas partir du début dans la recherche d'un bloc libre, mais de l'endroit de la dernière affectation, et la l'allocation ''best fit'' qui consiste à trouver un bloc libre de la bonne taille en premier. |
| 171 | 1. L'allocateur d'objets (nommés blocs dans le rappel de cours au-dessus) pour l'application utilise une politique ''first-fit''. Qu'est-ce que cela signifie ? Quels sont les autres ? Existe-t-il une politique meilleure que les autres et pour quel critère ? |
| 172 | {{{#!protected ------------------------------------------------------------------ |
| 173 | ''' |
| 174 | * L'allocation ''first-fit'' signifie que l'allocateur utilise le premier bloc libre assez grand pour l'objet alloué. Ce bloc libre est coupé en deux s'il est trop grand pour produire un nouveau bloc libre, mais plus petit parce qu’amputé de la partie allouée à l'objet. |
| 175 | * On a aussi l'allocation ''next-fit'' qui consiste à ne pas partir du début dans la recherche d'un bloc libre, mais de l'endroit de la dernière affectation, et la l'allocation ''best-fit'' qui consiste à trouver un bloc libre de la bonne taille en premier. |
309 | | == B.1. Transformer l'allocateur first fit et allocateur next fit |
310 | | |
311 | | L'allocateur first fit parcourt la liste des blocs depuis le tout premier jusqu'à la fin à la recherche du premier bloc non plein assez grand pour l'objet à allouer. |
312 | | |
313 | | |
314 | | == B.2. Transformer l'allocateur first/next fit et allocateur best fit |
| 309 | == B.1. Transformer l'allocateur first-fit et allocateur next-fit |
| 310 | |
| 311 | L'allocateur first-fit parcourt la liste des blocs depuis le tout premier jusqu'à la fin à la recherche du premier bloc non plein assez grand pour l'objet à allouer. Pour transformer ce comportement en next-fit, il suffit de se souvenir du dernier bloc alloué. |
| 312 | |
| 313 | Dans le code ci-après, on peut voir la fonction `try_malloc()` appelée par la fonction `malloc()`. |
| 314 | On voit que les blocs sont parcouru depuis `Heap.beg` le premier bloc jusqu'au dernier `Heap.end` (qui n'est pas vraiment un bloc mais une frontière). Lisez le code et trouvez comment recommencer le prochain `try_malloc()` à partir de dernier bloc alloué. Ce n'est pas difficile, mais il faut comprendre... |
| 315 | |
| 316 | {{{#!c |
| 317 | static size_t CacheLineSize; // cache line size set by malloc_init() |
| 318 | |
| 319 | typedef struct block_info_s { // small structure always put at the beginning of each blocks |
| 320 | unsigned full:1; // 1 full, 0 free (means empty) |
| 321 | unsigned magic:7; // MAGIC_HEAP : magic number to check the corruption |
| 322 | unsigned size:24; // Number of block_info to the next block_info |
| 323 | } block_info_t; |
| 324 | |
| 325 | static struct heap_s { // user Heap |
| 326 | block_info_t *beg; // Heap beginning |
| 327 | block_info_t *end; // Heap end |
| 328 | } Heap; |
| 329 | |
| 330 | #define LINE_FLOOR(p) (block_info_t *)FLOOR((size_t)(p),CacheLineSize) |
| 331 | #define LINE_CEIL(p) (block_info_t *)CEIL((size_t)(p),CacheLineSize) |
| 332 | #define BINFO_SZ sizeof(block_info_t) |
| 333 | |
| 334 | static void* try_malloc (size_t size) |
| 335 | { |
| 336 | size = CEIL (size+BINFO_SZ, CacheLineSize); // true required size in bytes |
| 337 | size = size / sizeof (block_info_t); // in the heap size is in block_info_t |
| 338 | block_info_t *oldnext, *newnext, *new; |
| 339 | |
| 340 | for (new = Heap.beg; // from the beginning of the Heap |
| 341 | (new < Heap.end) && (new->full||(new->size<size)); // while end not reached and no space |
| 342 | new += new->size); // go to next block |
| 343 | |
| 344 | if (new > Heap.end) return NULL; // end reached without finding space |
| 345 | |
| 346 | new->full = 1; // space found, we put the block |
| 347 | oldnext = new + new->size; // next block address before the cut |
| 348 | newnext = LINE_CEIL(new+size); // find the new next block |
| 349 | |
| 350 | if (newnext != oldnext) { // if we need to cut the find block |
| 351 | new->size = newnext - new; // new size of current block |
| 352 | new->magic = MAGIC_HEAP; // to try detect Heap corruption |
| 353 | newnext->size = oldnext - newnext; // new size of remainning space |
| 354 | newnext->full = 0; // that is free space |
| 355 | newnext->magic = MAGIC_HEAP; // to try detect Heap corruption |
| 356 | } |
| 357 | return (void *)(new + 1); // the allocated block after block_info |
| 358 | } |
| 359 | |
| 360 | void * malloc (size_t size) |
| 361 | { |
| 362 | block_info_t *ptr = try_malloc (size); // Search for a block |
| 363 | if (ptr == NULL) { // if no free space |
| 364 | merge (Heap.beg); // merge all free blocks from beginning |
| 365 | ptr = try_malloc (size); // try again to find a block |
| 366 | } |
| 367 | return ptr; // return what you have found |
| 368 | } |
| 369 | }}} |
| 370 | |
| 371 | |
| 372 | == B.2. Transformer l'allocateur first-fit en allocateur best-fit |
| 373 | |
| 374 | Plus difficile, passer l'allocateur en best-fit. Je ne vous demande pas d'écrire le code, sauf si vous avez du temps et de la motivation. En revanche, vous pouvez réfléchir à la manière de procéder. Pour vous aidez, l'idée, c'est de ne pas toucher aux chaînages des blocs utilisés par first-fit. Il faut créer un chaînage ordonné par taille des blocs libres en utilisant l'API `list`. |