Librairie Malloc

Novembre 2020

Alexandra Demski

Dépôt Github du projet

Généralités

L'objectif principal du projet est d'implémenter mes propres fonctions d'allocation dynamique malloc, free, calloc et realloc en utilisant les appels système permettant de manipuler la limite supérieure du tas.

Le Projet

Les Fonctionnalités

Le projet va inclure les fonctions de base ainsi qu'un outil de debug.

Chaque bloque alloué comprendra une entête contenant toutes les informations administratives nécessaires au bon fonctionnement de malloc ainsi qu'un espace de données pour stocker des informations.

L'algorithme d'allocation va, dans un premier temps, chercher un bloque alloué libre dont la taille est suffisante. En cas de succès, il retourne l'adresse de la zone et indique le bloque comme utilisé, sinon, en cas d'échec, il crée un nouveau bloque en utilisant sbrk.

Avec cette implémentation minimaliste, désallouer un bloque en mémoire avec la fonction free va seulement changer son statut d'utilisé à libre.

L'outil de debug print_stats affichera des informations utiles comme le nombre total de bloque alloué, utilisé et libre, leur taille et la quantité d'espace gâché.

La Structure

Le projet est divisé en plusieurs fichier. La majeure partie du code est stockée dans memory.c qui possède également un header memory.h incluant les fonctions. Les nombreux fichiers test.c sont utilisés pour confirmer l'efficacité de la librairie. Le dernier fichier appelé Makefile permet tout simplement de compiler tout le code : on utilisera la commande make pour créer tous les fichiers executables nécessaires.

Le Code

Bloque

Un bloque de mémoire possède des informations utiles qui seront toutes stockées dans un header.

Cette structure de données fonctionne comme une liste chaînée : chaque bloque va pointer vers le précédent et le suivant. Le premier bloque de la liste sera appelé first et initialisé à NULL puisque malloc n'a pas encore été appelé.

Malloc

La première étape avant d'allouer un bloque est d'aligner la taille demandée. Cela permet de rendre le programme plus rapide et efficace. Ainsi, dans la fonction malloc nous allons appeler la méthode align qui retourne un multiple de 4 de la taille donnée.

La fonction multiple4 vérifie seulement si la taille donnée n'est pas déjà un multiple de 4 et qui donc n'a pas besoin d'être alignée.

Bien évidemment, après avoir aligné la taille, on vérifie si elle est inférieure ou égale à zéro pour ainsi éviter tout comportement anormal.

Après cela, on distingue deux possibilités : on utilise malloc pour la première fois et nous avons donc pas besoin de chercher de bloque libre ou on a déjà appelé malloc et on doit, par conséquence, parcourir la liste chaînée.

La fonction _new_block déplace le program break avec l'appel système sbrk et retourne le nouveau bloque créé.

La fonction _find_block cherche à travers la liste chaînée le bloque le plus optimal. Si la fonction n'en trouve pas, elle retourne NULL.

Free

Puisqu'il est impossible de désallouer l'espace mémoire avec sbrk la fonction free va seulement indiquer qu'un bloque est libre. Avant d'appeler la fonction, il est important de vérifier le pointeur passé en paramètre pour éviter des erreurs.

La fonction _block_ptr retourne l'adresse de l'espace alloué pour les données, sans l'en-tête.

Calloc

La fonction calloc utilisera notre mallo pour allouer un bloque et mettre ses bits à 0 avec la fonction memset.

Realloc

Tout comme calloc la fonction realloc va simplement appeler les fonctions malloc et free pour, tout d'abord, copier les données du bloque passé en paramètre vers un nouveau avec la fonction memcpy, puis libérer ce même bloque. Il est important de vérifier le pointeur passé en paramètre pour éviter toute erreur.

Les Améliorations

Pour améliorer la librairie, des fonctionnalités supplémentaires ont été ajoutées. En effet, notre librairie génère beaucoup de fragmentation et pour limiter son impact j'ai implémenté deux améliorations.

Division à l'allocation

Avant qu'un bloque libre soit alloué par la fonction _find_block, si sa taille est suffisamment grande, le bloque sera divisé en deux pour générer un nouveau bloque ajouté à la liste chaînée.

Fusionnement à la libération

L'amélioration complémentaire de la fonctionnalité précédente va fusionner les voisins d'un bloque à sa libération si eux aussi sont libres. Cette fonctionnalité fonctionne de façon similaire que la précédente mais au lieu d'ajouter un nouvel élément à la liste, on en supprime en les fusionnant.