Maison  >  Article  >  développement back-end  >  Écrire votre propre allocateur de pool de mémoire en C

Écrire votre propre allocateur de pool de mémoire en C

Linda Hamilton
Linda Hamiltonoriginal
2024-11-20 03:33:02819parcourir

Writing Your Own Memory Pool Allocator in C

Écrire votre propre allocateur de pool de mémoire en C : un guide étape par étape

En C, la gestion dynamique de la mémoire est un aspect crucial du développement de logiciels efficaces, en particulier dans les applications critiques en termes de performances. Bien que des fonctions telles que malloc() et free() dans la bibliothèque standard soient couramment utilisées, elles entraînent une surcharge et des limitations, telles que la fragmentation et des temps d'allocation plus lents lorsqu'elles sont appelées fréquemment. Une solution à ces problèmes consiste à créer un allocateur de pool de mémoire.

Dans ce blog, nous expliquerons comment écrire un simple allocateur de pool de mémoire à partir de zéro en C. En utilisant un pool de mémoire, nous pouvons pré-allouer un gros bloc de mémoire et le gérer manuellement, réduisant ainsi la fragmentation et améliorant la mémoire. performances d'allocation.

? Poursuivez la conversation sur Twitter(X) : @trish_07

Qu’est-ce qu’un allocateur de pool de mémoire ?

Un allocateur de pool de mémoire est une stratégie de gestion de mémoire personnalisée dans laquelle un gros bloc de mémoire est pré-alloué et de plus petits morceaux sont distribués au programme selon les besoins. Lorsque la mémoire n’est plus nécessaire, elle est renvoyée dans le pool pour être réutilisée. Cette approche permet une allocation et une désallocation plus rapides que l'utilisation directe de malloc() et free(), ainsi qu'une meilleure utilisation de la mémoire.

Voici comment fonctionne un pool de mémoire de base :

  • Pré-allouer un gros bloc de mémoire.
  • Divisez ce bloc en morceaux plus petits (blocs).
  • Gardez une trace des blocs inutilisés dans une liste gratuite.
  • Lorsqu'un blocage est demandé, allouez-le depuis le pool et renvoyez-le à l'appelant.
  • Lorsqu'un bloc est libéré, remettez-le dans la piscine.

Étape 1 : définir la structure du pool de mémoire

Nous commencerons par définir une structure simple pour le pool de mémoire et les blocs qu'il contient. Chaque bloc aura un pointeur vers le bloc suivant dans la liste libre, ce qui nous permettra d'allouer et de libérer rapidement de la mémoire.

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

#define POOL_SIZE 1024  // Total memory pool size

// Define a block structure with a pointer to the next free block
typedef struct Block {
    struct Block *next;
} Block;

// Define the MemoryPool structure
typedef struct {
    Block *freeList;
    unsigned char pool[POOL_SIZE]; // Pre-allocated pool
} MemoryPool;

Dans ce code :

  • POOL_SIZE est la taille totale du pool de mémoire. Nous allouerons un tableau statique pour simuler le pool.
  • La structure Block représente un seul morceau de mémoire et comprend un pointeur (suivant) qui le relie au bloc suivant dans la liste libre.
  • La structure MemoryPool contient le pointeur freeList (qui suit les blocs libres) et un tableau de pools qui contient la mémoire pré-alloué réelle.

Étape 2 : initialiser le pool de mémoire

Pour initialiser le pool de mémoire, nous devons diviser le pool en blocs et configurer la liste libre. Chaque bloc doit pointer vers le prochain bloc libre.

void initMemoryPool(MemoryPool *pool) {
    pool->freeList = (Block *)pool->pool;
    Block *current = pool->freeList;

    // Create a free list of blocks
    for (int i = 0; i < (POOL_SIZE / sizeof(Block)) - 1; i++) {
        current->next = (Block *)((unsigned char *)current + sizeof(Block));
        current = current->next;
    }

    current->next = NULL; // Last block points to NULL
}

Dans cette fonction :

  • Nous initialisons la freeList pour pointer vers le début du pool.
  • Nous parcourons ensuite le pool, en définissant le pointeur suivant de chaque bloc sur le suivant en mémoire.
  • Enfin, le dernier bloc pointe vers NULL pour indiquer la fin de la liste libre.

Étape 3 : Allocation de mémoire à partir du pool

Pour allouer de la mémoire, nous devons obtenir le premier bloc disponible de la liste libre. Une fois que nous attribuons un bloc, nous le supprimons de la liste gratuite.

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

#define POOL_SIZE 1024  // Total memory pool size

// Define a block structure with a pointer to the next free block
typedef struct Block {
    struct Block *next;
} Block;

// Define the MemoryPool structure
typedef struct {
    Block *freeList;
    unsigned char pool[POOL_SIZE]; // Pre-allocated pool
} MemoryPool;

Cette fonction vérifie si la liste gratuite est vide. Sinon, il prend le premier bloc libre, le supprime de la liste libre et le renvoie à l'appelant.

Étape 4 : Libérer de la mémoire et la rajouter au pool

Lorsque la mémoire est libérée, nous remettons le bloc dans la liste libre. Cela permet de le réutiliser pour des allocations futures.

void initMemoryPool(MemoryPool *pool) {
    pool->freeList = (Block *)pool->pool;
    Block *current = pool->freeList;

    // Create a free list of blocks
    for (int i = 0; i < (POOL_SIZE / sizeof(Block)) - 1; i++) {
        current->next = (Block *)((unsigned char *)current + sizeof(Block));
        current = current->next;
    }

    current->next = NULL; // Last block points to NULL
}

Ici, nous ajoutons le bloc libéré au début de la liste libre en définissant son pointeur suivant sur le premier bloc actuel de la liste libre. Cela permet au bloc d'être réutilisé à l'avenir.

Étape 5 : Exemple d'utilisation

Maintenant que nous disposons de toutes les fonctions nécessaires, rassemblons le tout et testons notre allocateur de pool de mémoire.

void *allocateMemory(MemoryPool *pool) {
    if (pool->freeList == NULL) {
        printf("Memory pool exhausted!\n");
        return NULL;
    }

    // Get the first free block
    Block *block = pool->freeList;
    pool->freeList = block->next; // Move the free list pointer

    return (void *)block;
}

Dans cet exemple :

  • Nous initialisons le pool de mémoire en utilisant initMemoryPool().
  • Nous allouons ensuite deux blocs en utilisant allocateMemory().
  • Enfin, nous libérons les blocs en utilisant freeMemory().

Lorsque vous exécutez ce programme, vous devriez voir un résultat similaire à celui-ci :

void freeMemory(MemoryPool *pool, void *ptr) {
    Block *block = (Block *)ptr;
    block->next = pool->freeList; // Add the block to the free list
    pool->freeList = block;
}

Pourquoi utiliser un pool de mémoire ?

  1. Performances : les pools de mémoire sont généralement plus rapides que les appels répétés de malloc() et free() car la surcharge de gestion de la mémoire au niveau du système est minimisée.
  2. Éviter la fragmentation : les pools de mémoire aident à éviter la fragmentation en allouant des blocs de mémoire de taille fixe.
  3. Prévisibilité : L'allocation de mémoire devient prévisible puisque le programme contrôle l'allocation et la désallocation.

Les pools de mémoire sont particulièrement utiles dans les systèmes en temps réel, les systèmes embarqués et les jeux, où la faible latence et l'efficacité de la mémoire sont essentielles.

Conclusion

L'écriture de votre propre allocateur de pool de mémoire peut optimiser considérablement la gestion de la mémoire pour les applications critiques en termes de performances. En gérant directement la mémoire, vous pouvez améliorer la vitesse d'allocation, réduire la fragmentation et mieux contrôler la façon dont la mémoire est utilisée dans votre programme. Bien que cet exemple soit basique, vous pouvez l'étendre avec des fonctionnalités supplémentaires telles que différentes tailles de bloc ou une allocation de mémoire thread-safe.

Si vous travaillez sur un projet qui nécessite une gestion efficace de la mémoire, envisagez de mettre en œuvre votre propre pool de mémoire. C'est un excellent moyen d'approfondir la gestion de la mémoire et d'améliorer les performances de votre application.


N'hésitez pas à nous contacter si vous avez des questions ou si vous avez besoin de précisions supplémentaires. Bon codage ! ?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn