Présentation du système d'allocation mémoire
Ce projet implémente un allocateur mémoire optimisé pour environnements multithreads, inspiré de tc-mimic (Thread-Caching Malloc). Il remplace les fonctions standard malloc et free pour améliorer l'efficacité et réduire la fragmentation.
Prérequis techniques
- Programmation C/C++ avancée
- Structures de données (listes chaînées, tables de hachage)
- Gestion mémoire des systèmes d'exploitation
- Modèle singleton et synchronisation multithread
Fonctionnement des pools mémoire
Un pool mémoire préalloue un bloc conséquent lors de l'initialisation. Les allocations ultérieures utilisent ce bloc plutôt que les appels système directs. Cette approche résout deux problèmes fondamentaux :
Optimisation des performances
Les appels système malloc impliquent des changements de contexte coûteux. Le pool effectue des opérations en espace utilisateur via des manipulations de pointeurs.
Contrôle de la fragmentation
Deux types de fragmentation sont adressés :
- Externe : Réduite par la gestion de blocs contigus
- Interne : Minimisée via des tailles d'allocation alignées
Pool à taille fixe
Spécialisé dans l'allocation d'objets de dimension constante, ce pool offre :
- Allocations en temps constant (O(1))
- Minimisation des conflits de verrous
- Élimination de la fragmentation externe
Implémnetation du pool fixe
template<typename Objet>
class PoolFixe {
std::vector<char*> blocs_memoire;
char* bloc_actuel = nullptr;
size_t octets_restants = 0;
void* liste_libre = nullptr;
public:
Objet* Allouer() {
if(liste_libre) {
void* suivant = *static_cast<void**>(liste_libre);
Objet* objet = static_cast<Objet*>(liste_libre);
liste_libre = suivant;
return objet;
}
// Logique d'allocation de nouveau bloc
}
void Liberer(Objet* obj) {
obj->~Objet();
*static_cast<void**>(obj) = liste_libre;
liste_libre = obj;
}
};
Architecture à trois niveaux
L'allocateur utilise une hiérarchie décentralisée :
- Cache Thread : Sans verrou, gère les petites allocations (≤256Ko)
- Cache Central : Synchronisé par verrous par compartiment, équilibre la charge
- Cache Page : Gère les blocs mémoire au niveau système et la fusion des pages
Cache Thread
class CacheThread {
ListeLibre listes[TAILLE_TABLE];
public:
void* Allouer(size_t taille) {
size_t index = CalculateurIndex(taille);
if(!listes[index].Vide())
return listes[index].Extraire();
return AcquérirDuCentral(index, taille);
}
};
Cache Central
class CacheCentral {
ListeEtendue listes_etendues[TAILLE_TABLE];
std::mutex verrous[TAILLE_TABLE];
Etendue* ObtenirEtendue(ListeEtendue& liste, size_t taille) {
// Logique d'acquisition d'étendue mémoire
}
};
Structure d'étendue mémoire
struct Etendue {
ID_PAGE id_depart;
size_t pages_total;
Etendue* suivant;
Etendue* precedent;
size_t compteur_utilisation;
void* liste_libre;
};
Cache Page
class CachePage {
ListeEtendue listes[PAGES_MAX + 1];
std::mutex verrou_global;
public:
Etendue* NouvelleEtendue(size_t pages) {
if(!listes[pages].Vide())
return listes[pages].ExtraireFront();
// Logique de fusion et d'allocation système
}
};
Mécanisme de fusion des pages
Le cache page combine les étendues adjacentes lors de la libération pour former des blocs plus grands, réduisant la fragmentation externe.
Tests de performance
Comparaison des temps d'exécution (cycles CPU) :
| Opération | new/delete | Pool fixe |
|---|---|---|
| 100k allocations | 15 800 | 2 300 |
| Libérations multiples | 12 500 | 1 900 |