Maison  >  Article  >  base de données  >  Exemple d'analyse de la fonction zmalloc de Redis

Exemple d'analyse de la fonction zmalloc de Redis

PHPz
PHPzavant
2023-05-27 17:50:401120parcourir

Regardons directement la fonction zmalloc personnalisée dans le code source de Redis (pas la dernière version). Cette fonction est utilisée exactement de la même manière que les fonctions classiques telles que malloc. La différence réside dans ses détails d'implémentation internes.

void *zmalloc(size_t taille) {

// Allouer de la mémoire ;

void *ptr = malloc(size + PREFIX_SIZE);

// L'échec de l'allocation génère une exception ;

Si (!ptr) zmalloc_oom_handler(size);

// Le système peut-il utiliser la fonction "malloc_size" ?

#ifdef HAVE_MALLOC_SIZE

Update_zmalloc_stat_alloc(zmalloc_size(ptr));

Retour ptr;

#autre

//Enregistrez la taille réelle des données allouées dans le champ de données ; *((size_t*)ptr) = taille;

// Calcule l'utilisation de la mémoire après l'alignement et met à jour la variable "used_memory"

 ; Update_zmalloc_stat_alloc(size + PREFIX_SIZE);

// Renvoie la position initiale du corps de données ;

Retour (char*)ptr + PREFIX_SIZE ;

#endif

}

En fait, la fonction malloc de la bibliothèque standard peut déjà aligner automatiquement la mémoire allouée, donc l'objectif principal de la méthode zmalloc ici est de calculer avec précision la taille de la mémoire allouée pour chaque stockage de données. Chaque fois que la mémoire est allouée, zmalloc ajoutera un espace mémoire supplémentaire de taille PREFIX_SIZE à la taille de mémoire de données allouée. Cette macro PREFIX_SIZE représente la taille maximale de l'espace d'adressage mémoire (size_t) du système actuel. Ici, nous pouvons faire référence à cet espace de taille PREFIX_SIZE comme partie « en-tête de données » d'une unité de stockage.

La structure des unités de stockage de la première version de Redis

Comme le montre la figure ci-dessus, via l'instruction *((size_t*)ptr) = size;, Redis stocke la taille réelle du bloc de données allouée dans les premiers octets PREFIX_SIZE du bloc de mémoire actuellement alloué, c'est-à-dire dans l'en-tête de données, et dans ce qui suit, les entités de données binaires sont en fait stockées dans l'espace mémoire de taille « taille ». La fonction nommée update_zmalloc_stat_alloc maintient ici une variable globale nommée used_memory en interne, qui accumule la taille de mémoire nouvellement allouée à chaque fois. La fonction renvoie un pointeur de décalage à la fin, pointant vers la partie du corps de données de la mémoire actuellement allouée. Les détails spécifiques d'implémentation de la fonction update_zmalloc_stat_alloc sont les suivants.

#define update_zmalloc_stat_alloc(__n) do {

taille_t _n = (__n);

// Complétion manuelle de la mémoire ;

Si (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); atomiqueIncr(used_memory, __n);

} pendant que(0)

La chose importante à noter ici est la ligne _n += sizeof(long)-(_n&(sizeof(long)-1));. La fonction macro entière détermine d'abord si la taille de la mémoire allouée cette fois est un multiple entier de sizeof(long) (les machines 64 bits correspondent à un alignement mémoire sur 8 octets ; les machines 32 bits correspondent à un alignement mémoire sur 4 octets), sinon Utilisez ensuite l'instruction que nous avons donnée précédemment pour ajouter l'espace réservé correspondant après le segment de données afin de constituer le nombre de bits nécessaire pour répondre aux exigences d'alignement de la mémoire (4/8 octets). La fonction atomicIncr finale est utilisée pour mettre à jour la valeur globale de la variable used_memory tout en garantissant la sécurité des threads.

Le processus de libération de mémoire et d'allocation de mémoire dans cette version de Redis est exactement le contraire. Le code ci-dessous correspond aux détails d'implémentation de la fonction "zfree" correspondante. Tout d'abord, la fonction pointe vers la première adresse du champ de données contenant la taille réelle du bloc de données via l'instruction (char*)ptr-PREFIX_SIZE (en passant à une adresse mémoire inférieure), puis obtient les données via l'instruction *(( size_t*)realptr). La taille réelle de la mémoire allouée par le bloc (à l'exclusion des zones d'alignement de la mémoire). Enfin, mettez à jour la valeur de la variable globale used_memory via la fonction update_zmalloc_stat_free et libérez le segment mémoire.

void zfree(void *ptr) {

#ifndef HAVE_MALLOC_SIZE

annuler *realptr;

size_t ancienne taille ;

#endif

Si (ptr == NULL) retourne ;

#ifdef HAVE_MALLOC_SIZE

Update_zmalloc_stat_free(zmalloc_size(ptr));

gratuit(ptr);

#autre

realptr = (char*)ptr-PREFIX_SIZE;

Oldsize = *((size_t*)realptr);

Update_zmalloc_stat_free(oldsize+PREFIX_SIZE);

gratuit(realptr);

#endif

}

Comme indiqué ci-dessous, si nous examinons les détails d'implémentation de la fonction update_zmalloc_stat_free, vous constaterez que son processus d'exécution est similaire à la fonction précédente update_zmalloc_stat_alloc. En calculant la taille des octets de mémoire qui doivent être complétés et en soustrayant la taille correspondante de l'espace mémoire de la variable used_memory, l'utilisation de l'espace mémoire peut être calculée avec précision.

#define update_zmalloc_stat_free(__n) do {

taille_t _n = (__n);

Si (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); atomicDecr(used_memory,__n);

} while(0) 

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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer