Allocation de mémoire système à l'aide du sous-système malloc

La mémoire est allouée aux applications qui utilisent le sous-système malloc .

Le sous-système malloc est une API de gestion de la mémoire qui comprend les sous-routines suivantes:

  • malloc
  • calloc
  • realloc
  • libérer
  • mallopt
  • mallinfo
  • alloca
  • valloc
  • alignme_posix_mémoire

Le sous-système malloc gère un objet mémoire logique appelé segment de mémoire. Le segment de mémoire est une région de mémoire qui réside dans l'espace adresse de l'application entre le dernier octet de données alloué par le compilateur et la fin de la région de données. Le segment de mémoire est l'objet de mémoire à partir duquel la mémoire est allouée et à laquelle la mémoire est renvoyée par l'API du sous-système malloc .

Le sous-système malloc effectue les opérations de mémoire fondamentales suivantes:
  • Attribution :

    Effectué par les sous-routines malloc, calloc valloc, allocaet posix_memalign .

  • Désallocation:

    Effectué par la sous-routine free .

  • Réallocation:

    Effectué par la sous-routine realloc .

Les sous-routines mallopt et mallinfo sont prises en charge pour la compatibilité System V. La sous-routine mallinfo peut être utilisée lors du développement de programme pour obtenir des informations sur le segment de mémoire géré par la sous-routine malloc . La sous-routine mallopt peut être utilisée pour désactiver la mémoire libre alignée sur la page et dimensionnée sur la page, et pour activer et désactiver l'allocateur par défaut. A l'instar de la sous-routine malloc , la sous-routine valloc est fournie à des fins de compatibilité avec la bibliothèque de compatibilité de Berkeley.

Pour plus d'informations, voir les sections suivantes:

Utilisation du segment de mémoire du processus

_edata est un symbole dont l'adresse est le premier octet suivant le dernier octet des données de programme initialisées. Le symbole _edata fait référence au début du segment de mémoire du processus, qui est agrandi par le sous-système malloc lorsque le premier bloc de données est alloué. Le sous-système malloc agrandit le segment de mémoire du processus en augmentant la valeur brk du processus, ce qui indique la fin du segment de mémoire du processus. Pour ce faire, vous appelez la sous-routine sbrk . Le sous-système malloc développe le segment de mémoire du processus en fonction des besoins de l'application.

Le segment de mémoire du processus est divisé en blocs de mémoire alloués et libérés . Le pool libre est constitué de la mémoire disponible pour l'allocation suivante. Une allocation est effectuée en retirant d'abord un bloc mémoire du pool libre, puis en renvoyant à la fonction appelante un pointeur vers ce bloc. Une réallocation est effectuée en allouant un bloc de mémoire de la nouvelle taille, en déplaçant les données du bloc d'origine vers le nouveau bloc et en libérant le bloc d'origine. Les blocs de mémoire alloués sont constitués des éléments du segment de mémoire du processus utilisés par l'application. Etant donné que les blocs de mémoire ne sont pas physiquement supprimés du segment de mémoire (ils passent de l'état libre à l'état alloué), la taille du segment de mémoire du processus ne diminue pas lorsque l'application libère de la mémoire.

Espace adresse de processus dans les applications 32 bits

Un programme d'application 32 bits exécuté sur le système possède un espace adresse divisé en plusieurs segments:

Segment Descriptif
0x00000000à0x0fffffff Contient le noyau.
0x10000000à0x1fffffff Contient le texte du programme d'application.
0x20000000à0x2fffffff Contient les données du programme d'application, le segment de mémoire du processus et la pile d'applications.
0x30000000à0xcfffffff Disponible pour une utilisation par la mémoire partagée ou les services mmap .
0xd0000000à0xdfffffff Contient le texte de la bibliothèque partagée.
0xe0000000à0xefffffff Disponible pour une utilisation par la mémoire partagée ou les services mmap .
0xf0000000à0xffffffff Contient les données de la bibliothèque partagée de l'application.

Espace adresse de processus dans les applications 64 bits

Un programme d'application 64 bits exécuté sur le système possède un espace adresse divisé en plusieurs segments:

Segment Descriptif
0x0000 0000 0000 0000à0x0000 0000 0fff ffff Contient le noyau.
0x0000 0000 f000 0000à0x0000 0000 ffff ffff Réservé.
0x0000 0001 0000 0000à0x07ff ffff ffff ffff Contient le texte du programme d'application, les données du programme d'application, le segment de mémoire du processus et la mémoire partagée ou les services mmap .
0x0800 0000 0000 0000à0x08ff ffff ffff ffff Objets chargés en privé.
0x0900 0000 0000 0000à0x09ff ffff ffff ffff Texte et données de la bibliothèque partagée.
0x0f00 0000 0000 0000à0x0fff ffff ffff ffff Pile d'applications.
Remarque : AIX utilise une technique d'allocation différée des emplacements de pagination pour le stockage alloué aux applications. Lorsque du stockage est alloué à une application avec un sous-programme, tel que malloc, aucun espace de pagination n'est affecté à ce stockage tant que le stockage n'est pas référencé. Cette technique est utile pour les applications qui allouent des segments de mémoire épars de grande taille. Toutefois, cette technique peut affecter la portabilité des applications qui allouent de très grandes quantités de mémoire. Si l'application s'attend à ce que les appels à malloc échouent lorsqu'il n'y a pas suffisamment de stockage de secours pour prendre en charge la demande de mémoire, l'application peut allouer trop de mémoire. Lorsque cette mémoire est référencée ultérieurement, la machine est rapidement à court d'espace de pagination et le système d'exploitation arrête les processus de sorte que le système n'est pas complètement épuisé de mémoire virtuelle. L'application qui alloue de la mémoire doit s'assurer que le stockage de secours existe pour le stockage alloué. La définition de la variable d'environnement PSALLOC sur PSALLOC=early modifie la technique d'allocation d'espace de pagination en un algorithme d'allocation précoce. En allocation anticipée, l'espace de pagination est affecté une fois que la mémoire est demandée. Pour plus d'informations, voir Espace de pagination et mémoire virtuelle dans Gestion des systèmes d'exploitation et des unités.

Description de la règle d'allocation système

La règle d'allocation fait référence à l'ensemble des structures de données et des algorithmes utilisés pour représenter le segment de mémoire et pour implémenter l'allocation, la désallocation et la réallocation. Le sous-système malloc prend en charge plusieurs règles d'allocation différentes, notamment la règle d'allocation par défaut, la règle d'allocation watson, la règle d'allocation malloc 3.1 et la règle d'allocation définie par l'utilisateur. L'API permettant d'accéder au sous-système malloc est identique pour toutes les stratégies d'allocation ; seule l'implémentation sous-jacente est différente.

Vous pouvez utiliser les variables d'environnement suivantes pour spécifier la règle d'allocation et toute option normale ou de débogage pour cette règle:
  • MALLOCTYPE indique la règle d'allocation.
  • MALLOCOPTIONS spécifie des options normales pour la règle d'allocation choisie.
  • MALLOCDEBUG indique les options de débogage de la règle d'allocation choisie.
  • MALLOCALIGN indique l'alignement malloc par défaut externe à un programme.

La règle d'allocation par défaut est généralement plus efficace et constitue le choix préféré pour la majorité des applications. Les autres règles d'allocation possèdent des caractéristiques comportementales uniques qui peuvent être bénéfiques dans des circonstances spécifiques, comme décrit dans la rubrique Comparaison des différentes règles d'allocation.

Certaines options des différentes politiques d'allocation sont compatibles entre elles et peuvent être utilisées en tandem. Lorsque vous utilisez des options en tandem, utilisez une virgule (,) pour séparer les options spécifiées par les variables d'environnement MALLOCOPTIONS et MALLOCDEBUG .

La variable d'environnement MALLOCALIGN peut être définie sur l'alignement par défaut souhaité pour chaque allocation malloc () . Par exemple:
MALLOCALIGN=16;  export MALLOCALIGN
La variable d'environnement MALLOCALIGN peut être définie sur n'importe quelle puissance de 2 valeurs supérieures ou égales à la taille d'un pointeur dans le mode d'exécution correspondant (4 octets pour le mode 32 bits, 8 octets pour le mode 64 bits). Pour les programmes compatibles avec les vecteurs 32 bits, cette variable d'environnement peut être définie sur 16, de sorte que tous les malloc ()s seront correctement alignés pour les types de données vectorielles si nécessaire. Notez que les programmes vectoriels 64 bits recevront déjà des allocations alignées sur 16 octets.

De plus, en interne à un programme, le programme peut utiliser la routine mallopt (M_MALIGN, 16) pour modifier la valeur par défaut malloc () afin de fournir des allocations alignées sur 16 octets. La routine mallopt (M_MALIGN) permet à un programme de contrôler dynamiquement l'alignement malloc par défaut lors de l'exécution.

Description de la règle d'allocation par défaut

La règle d'allocation par défaut gère l'espace disponible dans le segment de mémoire en tant que noeuds dans une arborescence de recherche binaire cartésienne dans laquelle les noeuds sont classés de gauche à droite par adresse (augmentation de l'adresse à droite) et de haut en bas par longueur (de sorte qu'aucun enfant ne soit plus grand que son parent). Cette structure de données n'impose aucune limitation sur le nombre de tailles de bloc prises en charge par l'arbre, ce qui permet une large gamme de tailles de bloc potentielles. Les techniques de réorganisation d'arborescence optimisent les temps d'accès pour l'emplacement, l'insertion et la suppression des noeuds et protègent également contre la fragmentation.

La règle d'allocation par défaut prend en charge les fonctions facultatives suivantes:

Affectation

Une petite quantité de temps système est nécessaire pour traiter une demande d'allocation. Ceci est dû à la nécessité d'un préfixe de métadonnées et à la nécessité d'un alignement approprié de chaque bloc de mémoire. La taille du préfixe de métadonnées pour toutes les allocations est de 8 et 16 octets pour les programmes 32 bits et 64 bits respectivement. Chaque bloc doit être aligné sur une limite de 16 ou 32 octets, donc la quantité totale de mémoire requise pour une allocation de taille n est:

size = roundup(n + prefix_size, alignment requirement)

Par exemple, une allocation de taille 37 dans un processus 32 bits nécessiterait roundup(37 + 8, 16), ce qui correspond à 48 octets.

Le noeud de l'arborescence dont l'adresse la plus basse est supérieure ou égale à la taille requise est supprimé de l'arborescence. Si le bloc trouvé est plus grand que la taille requise, le bloc est divisé en deux blocs: l'un de la taille requise, et l'autre un reste. Le deuxième bloc, appelé runt, est renvoyé à l'arbre libre pour une allocation future. Le premier bloc est renvoyé à l'appelant.

Si un bloc de taille suffisante n'est pas trouvé dans l'arbre libre, le tas est étendu, un bloc de la taille de l'extension acquise est ajouté à l'arbre libre, et l'allocation se poursuit comme décrit précédemment.

Désallocation

Les blocs de mémoire libérés avec la sous-routine free sont renvoyés à l'arborescence, à la racine. Chaque noeud du chemin d'accès au point d'insertion du nouveau noeud est examiné pour voir s'il est accolé au noeud en cours d'insertion. Si c'est le cas, les deux noeuds sont fusionnés et le noeud nouvellement fusionné est déplacé dans l'arborescence. Si aucun bloc adjacent n'est trouvé, le noeud est simplement inséré à l'endroit approprié dans l'arbre. La fusion de blocs adjacents peut réduire de manière significative la fragmentation du segment de mémoire.

Réaffectation

Si la taille du bloc réalloué est supérieure à celle du bloc d'origine, le bloc d'origine est renvoyé à l'arbre libre avec la sous-routine free de sorte que toute coalescence possible puisse se produire. Un nouveau bloc de la taille demandée est ensuite alloué, les données sont déplacées du bloc d'origine vers le nouveau bloc, et le nouveau bloc est renvoyé à l'appelant.

Si la taille du bloc réalloué est inférieure à celle du bloc d'origine, le bloc est divisé et le plus petit est renvoyé à l'arbre libre.

Restrictions

Description de la règle d'allocation watson

La règle d'allocation Watson gère l'espace disponible dans le segment de mémoire sous la forme de noeuds dans deux arbres rouge-noir distincts: l'un trié par adresse, l'autre par taille. Les arbres rouge-noir fournissent des opérations d'arbre plus simples et plus efficaces que les arbres cartésiens de l'allocateur par défaut, de sorte que la stratégie d'allocation watson est souvent plus rapide que la valeur par défaut.

Affectation

La règle d'allocation Watson a les mêmes exigences de surcharge que la règle d'allocation par défaut.

L'arbre de taille est recherché pour le plus petit bloc possible supérieur ou égal à la taille requise. Ce bloc est ensuite supprimé de l'arbre de taille. Si le bloc trouvé est plus grand que la taille requise, le bloc est divisé en deux blocs: un bloc de la taille restante et le second de la taille requise. Le premier bloc, appelé runt, est renvoyé à l'arborescence des tailles pour une allocation ultérieure. Le deuxième bloc est renvoyé à l'appelant. Si le bloc trouvé dans l'arborescence des tailles correspond exactement à la taille requise, le bloc est supprimé de l'arborescence des tailles et des adresses, puis renvoyé à l'appelant.

Si un bloc de taille suffisante n'est pas trouvé dans l'arbre libre, le segment de mémoire du processus est étendu, un bloc de la taille de cette extension est ajouté à la taille et aux arborescences d'adresses, et l'allocation se poursuit comme décrit précédemment.

Désallocation

Les blocs de mémoire alloués avec la sous-routine free sont renvoyés à l'arborescence d'adresses à la racine. Chaque noeud du chemin d'accès au point d'insertion du nouveau noeud est examiné pour voir s'il est accolé au noeud en cours d'insertion. Si c'est le cas, les deux noeuds sont fusionnés et le noeud nouvellement fusionné est déplacé dans l'arbre de taille. Si aucun bloc adjacent n'est trouvé, le noeud est simplement inséré à l'endroit approprié dans l'arbre d'adresse et de taille.

Après l'insertion, les deux arbres rouge-noir doivent être vérifiés pour un équilibrage correct.

Réaffectation

Si la taille du bloc réalloué est supérieure à celle du bloc d'origine, le bloc d'origine est renvoyé aux arbres libres avec la sous-routine free afin que toute coalescence possible puisse se produire. Un nouveau bloc de la taille demandée est ensuite alloué, les données sont déplacées du bloc d'origine vers le nouveau bloc, et le nouveau bloc est renvoyé à l'appelant.

Si la taille du bloc réalloué est inférieure à celle du bloc d'origine, le bloc est divisé et le reste est renvoyé à l'arbre libre.

Restrictions

La stratégie d'allocation Watson prend en charge les options suivantes:

Description de la règle d'allocation malloc 3.1

La règle d'allocation malloc 3.1 peut être sélectionnée en définissant MALLOCTYPE=3.1 avant le démarrage du processus. Par la suite, tous les programmes 32 bits exécutés par le shell utiliseront la règle d'allocation malloc 3.1 (les programmes 64 bits continueront d'utiliser la règle d'allocation par défaut).

La règle d'allocation malloc 3.1 gère le segment de mémoire sous la forme d'un ensemble de 28 compartiments de hachage, chacun pointant vers une liste liée. Chaque liste liée contient des blocs d'une taille particulière. L'index dans les compartiments de hachage indique la taille des blocs de la liste liée. La taille du bloc est calculée à l'aide de la formule suivante:
size = 2 i + 4
i identifie le compartiment. Cela signifie que les blocs de la liste ancrés par le seau zéro sont de 20 + 4 = 16 octets de long. Par conséquent, étant donné qu'un préfixe a une taille de 8 octets, ces blocs peuvent satisfaire des demandes de blocs d'une longueur comprise entre 0 et 8 octets. Le tableau suivant illustre la répartition des tailles demandées entre les compartiments.
Remarque: cet algorithme peut utiliser jusqu'à deux fois la quantité de mémoire réellement demandée par l'application. Une page supplémentaire est requise pour les compartiments de plus de 4096 octets car les objets d'une page de taille supérieure ou supérieure sont alignés sur la page. Etant donné que le préfixe précède immédiatement le bloc, une page entière est requise uniquement pour le préfixe.
Compartiment Taille de bloc Tailles mappées Pages utilisées
0 16 0... 8  
1 32 9... 24  
2 64 25... 56  
3 128 57... 120  
4 256 121... 248  
5 512 249... 504  
6 1K 505... 1K-8  
7 2K 1K-7 ... 2K-8  
8 4K 2K-7 ... 4K-8 2
9 8K 4K-7 ... 8K-8 3
10 16K 8K-7 ... 16K-8 5
11 32K 16K-7 ... 32K-8 9
12 64K 32K-7 ... 64K-8 17
13 128K 64K-7 ... 128K-8 33
14 256K 128K-7 ... 256K-8 65
15 512K 256K-7 ... 512K-8 129
16 1M 256K-7 ... 1M-8 257
17 2M 1M-7 ... 2M-8 513
18 4M 2M-7 ... 4M-8 1K + 1
19 8M 4M-7 ... 8M-8 2K + 1
20 16M 8M-7 ... 16M-8 4K + 1
21 32M 16M-7 ... 32M-8 8K + 1
22 64M 32M-7 ... 64M-8 16K + 1
23 128M 64M-7 ... 128M-8 32K + 1
24 256M 128M-7 ... 256M-8 64K + 1
25 512M 256M-7 ... 512M-8 128K + 1
26 1024M 512M-7 ... 1024M-8 256K + 1
27 2048M 1024M-7 ... 2048M-8 512K + 1

Affectation

Un bloc est alloué à partir du pool libre en convertissant d'abord les octets demandés en un index dans le tableau d'intervalles, à l'aide de l'équation suivante:

needed = requested + 8

If needed <= 16,
then
bucket = 0

If needed > 16,
then
bucket = (log(needed)/log(2) rounded down to the nearest integer) - 3

La taille de chaque bloc de la liste ancrée par le compartiment estblock size = 2 bucket + 4: Si la liste dans le compartiment est null, la mémoire est allouée à l'aide de la sous-routine sbrk pour ajouter des blocs à la liste. Si la taille de bloc est inférieure à une page, une page est allouée à l'aide de la sous-routine sbrk et le nombre de blocs obtenu en divisant la taille de bloc par la taille de page est ajouté à la liste. Si la taille de bloc est supérieure ou égale à une page, la mémoire nécessaire est allouée à l'aide de la sous-routine sbrk et un seul bloc est ajouté à la liste des éléments disponibles pour le compartiment. Si la liste libre n'est pas vide, le bloc en tête de la liste est renvoyé à l'appelant. Le bloc suivant de la liste devient alors la nouvelle tête.

Désallocation

Lorsqu'un bloc de mémoire est renvoyé au pool libre, l'index de compartiment est calculé comme avec l'allocation. Le bloc à libérer est ensuite ajouté à la tête de la liste des libres du godet.

Réaffectation

Lorsqu'un bloc de mémoire est réalloué, la taille requise est comparée à la taille existante du bloc. En raison de la grande variance des tailles gérées par un seul compartiment, la nouvelle taille de bloc est souvent mappée au même compartiment que la taille de bloc d'origine. Dans ces cas, la longueur du préfixe est mise à jour pour refléter la nouvelle taille et le même bloc est renvoyé. Si la taille requise est supérieure au bloc existant, le bloc est libéré, un nouveau bloc est alloué à partir du nouveau compartiment et les données sont déplacées de l'ancien bloc vers le nouveau bloc.

Restrictions

Le paramètre MALLOCTYPE=3.1 active uniquement la règle malloc 3.1 pour les programmes 32 bits. Pour que les programmes 64 bits puissent utiliser la règle malloc 3.1 , la variable d'environnement MALLOCTYPE doit être explicitement définie sur MALLOCTYPE=3.1_64BIT. Cette règle d'allocation est moins efficace que la règle par défaut et n'est pas recommandée dans la plupart des cas.

La stratégie d'allocation malloc 3.1 prend en charge les options suivantes:

Description de la règle d'allocation de pool

Le pool Malloc est un système frontal hautes performances pour les fonctions libc malloc, calloc, free, posix_memalign et realloc pour la gestion des objets de stockage inférieurs à 513 octets. Les avantages en termes de performances proviennent de chemins d'accès considérablement plus courts et d'une meilleure utilisation du cache de données. Pour les applications à unités d'exécution multiples, les ancrages de pool local d'unités d'exécution permettent également d'éviter les opérations atomiques. Cette interface frontale peut être utilisée avec n'importe quel schéma de gestion de stockage actuellement fourni dans libc (yorktownet watson).

Pour utiliser le pool malloc , exécutez la commande suivante:
export MALLOCOPTIONS=pool<:max_size>

Lorsque cette option est spécifiée, une collection de pools est créée lors de l'initialisation de malloc où chaque pool est une liste liée d'objets de taille fixe. Le plus petit pool peut contenir des objets de taille de pointeur (tels que 8 octets pour les applications 32 bits ou 16 octets pour les applications 64 bits). Chaque pool successif peut accueillir des objets dont la taille est supérieure à celle du pool précédent. Cela signifie qu'il existe 128 pools pour les applications 32 bits et 64 pools pour les applications 64 bits. La collection de pools est représentée sous la forme d'un tableau de pointeurs qui "ancrent" les listes liées.

Le pool Malloc utilise sa propre mémoire, le segment de mémoire du pool, qui n'est pas partagé avec mallocstandard. Lorsqu'elle est spécifiée, l'option max_size est arrondie à la valeur supérieure suivante de 2 Mo et est utilisée pour contrôler la taille du segment de mémoire du pool. L'option max_size peut être spécifiée sous la forme d'un nombre décimal ou d'un nombre hexadécimal précédé de 0x ou 0X (par exemple, export MALLOCOPTIONS=pool:0x1700000 définira max_size à 24 Mo après l'arrondi.

Pour les applications 32 bits, la taille du segment de mémoire du pool commence à 2 Mo. Si plus de mémoire est requise et que le segment de mémoire total du pool est inférieur à taille_max, 2 Mo supplémentaires sont acquis. Chaque zone de 2 Mo se trouvera sur une limite de 2 Mo, mais il n'est pas nécessaire qu'elle soit contiguë à l'une des autres zones de 2 Mo. Pour les applications 64 bits, un seul segment de mémoire de pool contigu de max_size est alloué lors de l'initialisation de malloc et n'est jamais étendu. Si max_size n'est pas spécifié, la valeur par défaut est 512 Mo pour les applications 32 bits et 32 Mo pour les applications 64 bits. Pour les modes 32 et 64 bits, max_size est défini sur 512 Mo si une taille supérieure est spécifiée. Pour le mode 32 bits, max_size est défini sur 512MBet pour le mode 64 bits, max_size est défini sur 3.7 Go si une taille supérieure est spécifiée.

Utilisation du Stockage

Tous les ancrages de pool sont initialement définis sur NULL ou vides. Lorsque le pool malloc sert une demande et que le pool correspondant est vide, une routine est appelée pour allouer de la mémoire à partir du segment de mémoire du pool en blocs contigus de 1024 octets sur des limites de 1024 octets. Plusieurs objets de la taille demandée sont "créés". L'adresse de la première est renvoyée pour satisfaire la demande, tandis que les objets restants sont liés entre eux et placés sur l'ancre du pool. Pour chaque bloc de 1024 octets, il existe une entrée de 2 octets dans une table auxiliaire qui est utilisée par free pour déterminer la taille d'un objet renvoyé.

Lorsqu'un objet est libéré par le pool malloc , il est simplement "inséré" dans l'ancrage de pool approprié. Aucune tentative n'est effectuée pour coalescer des blocs afin de créer des objets de plus grande taille.

En raison de ce comportement, le pool malloc peut utiliser plus de mémoire que les autres formes de malloc.

Alignement

L'alignement par défaut des sous-routines malloc (), calloc ()et realloc () doit être spécifié en définissant la variable d'environnement MALLOCALIGN de manière appropriée. La sous-routine posix_memalign () continue de fonctionner même si la variable d'environnement MALLOCALIGN n'est pas définie. Si MALLOCALIGN est supérieur à 512, le pool malloc n'est pas utilisé.

Efficacité de la mémoire cache

Les objets mémoire alloués avec le pool malloc n'ont pas de préfixes ni de suffixes. Les lignes de cache de données sont donc plus densément remplies de données utilisables par l'application. Comme tous les objets mémoire dont la puissance est égale à 2 sont alignés sur une limite égale à cette taille, chaque objet est contenu dans le nombre minimal de lignes de cache. Les sous-routines malloc et free n'analysent pas les arborescences ou les listes liées et ne " polluent donc pas le cache.

Prise en charge à unités d'exécution multiples

Les pools Malloc peuvent améliorer les performances de manière significative dans un scénario à unités d'exécution multiples car ils réduisent les conflits d'accès et le besoin d'opérations atomiques.

Prise en charge de l'équilibrage de charge

Dans certains scénarios à unités d'exécution multiples, le pool libre d'une unité d'exécution peut devenir très important en raison de la libération répétée de la mémoire allouée de manière dynamique. Toutefois, il se peut que d'autres unités d'exécution ne puissent pas utiliser cette mémoire.

La prise en charge de l'équilibrage de charge permet à une unité d'exécution de libérer la moitié de la mémoire de chaque pool dans un pool global une fois que le pool a atteint une valeur de seuil afin que les autres unités d'exécution puissent l'utiliser. Vous pouvez optimiser les valeurs de seuil auxquelles un pool d'unités d'exécution sera réajusté.

Pour activer la prise en charge de l'équilibrage de charge, les options suivantes doivent être exportées:

export MALLOCOPTIONS=pool:0x80000000,pool_balanced
export MALLOCFREEPOOL=min_size<-max_size>:threshold_value<,min_size<-max_size>:
threshold_value, ... >,default:threshold
L'exemple suivant définit la valeur de seuil pour les pools qui fournissent une mémoire de 0 à 16 octets et 256 blocs, et la valeur de seuil du pool qui sert des blocs de 32 octets à des blocs de 512 octets. Pour le reste des pools, les blocs de 128 octets sont la valeur de seuil.
export MALLOCFREEPOOL=0-16:256,32:512,default:128

Prise en charge du débogage

Il n'existe pas de version de débogage de ce système frontal hautes performances. Si la variable d'environnement MALLOCDEBUG est définie, l'option de pool est ignorée. Il est prévu que les applications soient déboguées à l'aide de malloc "normal" avant l'activation de la mise en pool.

Description de la règle d'allocation définie par l'utilisateur

Le sous-système malloc fournit un mécanisme par lequel les utilisateurs peuvent développer leurs propres algorithmes pour gérer le segment de mémoire du système et allouer de la mémoire.

Description de l'option no_overwrite

Une option supplémentaire disponible pour toutes les règles d'allocation est no_overwrite. Pour réduire la surcharge du code glink dans le sous-système malloc, le descripteur de fonction pour les API du sous-système malloc est remplacé par le descripteur de fonction pour l'implémentation sous-jacente réelle. Etant donné que certains programmes, tels que les débogueurs tiers, peuvent ne pas fonctionner lorsque des pointeurs de fonction sont modifiés de cette manière, l'option no_overwrite peut être utilisée pour désactiver cette optimisation.

Pour désactiver cette optimisation, définissez MALLOCOPTIONS=no_overwrite avant le démarrage du processus.

Comparaison des différentes règles d'allocation

Les différentes politiques d'allocation de malloc élaborées ci-dessus offrent une flexibilité aux développeurs d'applications lorsqu'elles sont utilisées séparément ou combinées de manière prise en charge. Il incombe au développeur de reconnaître les besoins uniques d'une application et d'optimiser les différents paramètres de la règle d'allocation de manière avantageuse.

Comparaison des règles d'allocation par défaut et malloc 3.1

Etant donné que la règle d'allocation malloc 3.1 arrondit la taille de chaque demande d'allocation à la puissance suivante de 2, elle peut générer une fragmentation considérable de la mémoire virtuelle et réelle et une mauvaise localisation de la référence. La règle d'allocation par défaut est généralement un meilleur choix car elle alloue exactement la quantité d'espace demandée et est plus efficace pour récupérer les blocs de mémoire précédemment utilisés.

Malheureusement, certains programmes d'application peuvent dépendre par inadvertance des effets secondaires de la règle d'allocation malloc 3.1 pour des performances acceptables ou même pour un fonctionnement correct. Par exemple, un programme qui dépasse la fin d'un tableau peut fonctionner correctement lors de l'utilisation de l'allocateur malloc 3.1 uniquement en raison de l'espace supplémentaire fourni par le processus d'arrondi. Le même programme est susceptible de connaître un comportement erratique ou même d'échouer lorsqu'il est utilisé avec l'allocateur par défaut car l'allocateur par défaut n'alloue que le nombre d'octets requis.

Comme autre exemple, en raison de la récupération d'espace inefficace de l'algorithme d'allocation malloc 3.1 , le programme d'application reçoit presque toujours de l'espace qui a été mis à zéro (lorsqu'un processus touche une page donnée dans son segment de travail pour la première fois, cette page est mise à zéro). Les applications peuvent dépendre de cet effet secondaire pour une exécution correcte. En fait, la mise à zéro de l'espace alloué n'est pas une fonction spécifiée de la sous-routine malloc et entraînerait une pénalité de performances inutile pour les programmes qui s'initialisent uniquement selon les besoins et qui ne sont peut-être pas à zéro. Etant donné que l'allocateur par défaut est plus agressif dans la réutilisation de l'espace, les programmes qui dépendent de la réception de la mémoire mise à zéro de malloc échoueront probablement lorsque l'allocateur par défaut sera utilisé.

De même, si un programme réalloue continuellement une structure à une taille légèrement supérieure, l'allocateur malloc 3.1 n'a peut-être pas besoin de déplacer la structure très souvent. Dans de nombreux cas, la sous-routine realloc peut utiliser l'espace supplémentaire fourni par l'arrondi implicite dans l'algorithme d'allocation malloc 3.1 . L'allocateur par défaut doit généralement déplacer la structure vers une zone légèrement plus grande en raison de la probabilité que quelque chose d'autre ait été appelé par la sous-routine malloc juste au-dessus. Cela peut présenter l'apparence d'une dégradation des performances de la sous-routine realloc lorsque l'allocateur par défaut est utilisé à la place de l'allocateur malloc 3.1 . En réalité, c'est le surfaçage d'un coût qui est implicite dans la structure du programme d'application.

Débogage de la mauvaise gestion de l'application du segment de mémoire système

Le sous-système malloc offre une collection d'outils de débogage destinés à aider le développeur d'applications à déboguer et à corriger les erreurs dans la gestion du segment de mémoire d'un programme. Ces outils de débogage sont contrôlés via la variable d'environnement MALLOCDEBUG .

Synopsis de la variable d'environnement malloc et des options

Le tableau suivant montre la compatibilité entre les variables d'environnement MALLOCTYPE et MALLOCOPTIONS .
Tableau 1. Compatibilité entre les variables d'environnement MALLOCTYPE et MALLOCOPTIONS
  multiheap (et sous-options) compartiments (et sous-options) Cache d'unité d'exécution décliner no_overwrite
Allocateur par défaut yes yes yes yes yes
3.1 non non yes yes yes
Watson non non non non non
Watson2 non non non non non
utilisateur: non non non non yes
Tableau 2. Compatibilité entre les variables d'environnement MALLOCDEBUG et MALLOCTYPE
  York Town < Localisateur par défaut > 3.1 Watson Watson2 utilisateur:
catch_overflow (et sous-options) yes non yes yes non
dotations de rapport yes non yes yes non
postfree_chèque yes non yes yes non
validate_ptrs yes non yes yes non
trace yes non yes yes non
log yes non yes yes non
verbose non non non non non
Toutes les options MALLOCDEBUG sont compatibles et prises en charge avec MALLOCOPTIONS.

Description de la règle d'allocation Watson2

Le sous-système malloc Watson2 s'adapte au comportement de l'application lorsqu'elle passe d'une unité d'exécution unique à plusieurs unités d'exécution et de plusieurs unités d'exécution à une seule unité d'exécution. Il utilise un mécanisme spécifique à l'unité d'exécution qui utilise un nombre variable de structures de segment de mémoire, qui dépendent du comportement du programme. Par conséquent, aucune option de configuration n'est requise. Le sous-système malloc Watson2 a O (logN) amorti le coût par opération pour de nombreuses charges de travail car un grand nombre d'opérations peuvent être exécutées à un moment constant sans synchronisation.

Affectation

L'allocation est gérée par une combinaison de mécanismes. Ces mécanismes dépendent de paramètres, tels que le nombre d'unités d'exécution actives, la taille de la demande et l'historique de libération du processus. L'ensemble de mécanismes est atteint à partir d'une mise en cache spécifique à une unité d'exécution et utilise un nombre variable de segments de mémoire, qui a une affinité d'unité d'exécution avec un arbre double-rouge-noir et une coalescence basée sur une page.

Désallocation

La désallocation dépend des mêmes paramètres que le comportement d'allocation. En règle générale, un bloc de retour est capturé dans le cache spécifique à l'unité d'exécution. En fonction de l'affinité de segment de mémoire et de l'utilisation de la capacité, la mémoire peut être renvoyée à l'une des structures de segment de mémoire multiples. Parfois, le contenu de la structure de segments de mémoire multiples est consolidé en une structure de segments de mémoire commune afin d'améliorer la coalescence et de réduire la fragmentation du segment de mémoire. Pour améliorer la robustesse vis-à-vis des erreurs d'application, l'allocateur identifie la désallocation de pointeurs non valides ou de blocs endommagés, dans une certaine mesure et filtre ces opérations.

Réaffectation

Les grands blocs de mémoire adéquats sont réutilisés. Si le bloc en cours ne peut pas satisfaire la demande, il est remplacé par une désallocation et une allocation régulières.

Restrictions

Le sous-système malloc Watson2 est adaptatif à l'application et ne nécessite aucune autre option, mais le sous-système malloc Watson2 prend en charge les fonctions de débogage suivantes qui sont contrôlées par la variable MALLOCDEBUG : validate_ptrs, report_allocations, et trace. Les rapports liés aux allocations peuvent être redirigés vers un fichier à l'aide de l'option output:<filename> . Voir Debug malloc tool pour des informations détaillées sur la variable MALLOCDEBUG .