Ressortingctions d’alignement pour malloc () / free ()

Les versions plus anciennes de K & R (2e éd.) Et d’autres textes en langage C que j’ai lues traitent de la mise en œuvre d’un allocateur de mémoire dynamic dans le style de malloc() et free() mentionnent également, en passant, quelque chose au sujet des ressortingctions d’alignement des types de données. Apparemment, certaines architectures matérielles (CPU, registres et access à la mémoire) restreignent la manière dont vous pouvez stocker et adresser certains types de valeur. Par exemple, il peut être nécessaire de stocker un entier de 4 octets ( long ) commençant aux adresses multiples de quatre.

Quelles ressortingctions, le cas échéant, les principales plates-formes (Intel et AMD, SPARC, Alpha) imposent-elles en matière d’allocation de mémoire et d’access à la mémoire ou puis-je ignorer en toute sécurité l’alignement des allocations de mémoire sur des limites d’adresses spécifiques?

Sparc, MIPS, Alpha et la plupart des autres architectures “RISC classiques” ne permettent que des access alignés à la mémoire, même de nos jours. Un access non aligné provoquera une exception, mais certains systèmes d’exploitation gèreront cette exception en le copiant à partir de l’adresse souhaitée dans le logiciel en utilisant des charges et des magasins plus petits. Le code de l’application ne saura pas qu’il y avait un problème, sauf que les performances seront très mauvaises.

MIPS a des instructions spéciales (lwl et lwr) permettant d’accéder à des quantités de 32 bits à partir d’adresses non alignées. Chaque fois que le compilateur peut dire que l’adresse est probablement non alignée, il utilisera cette séquence de deux instructions au lieu d’une instruction lw normale.

x86 peut gérer les access mémoire non alignés dans le matériel sans exception, mais il rest un impact sur les performances pouvant aller jusqu’à 3X par rapport aux access alignés.

Ulrich Drepper a rédigé un article complet sur ce sujet et d’autres sujets liés à la mémoire, intitulé Ce que chaque programmeur devrait savoir sur la mémoire . C’est une très longue écriture, mais remplie de bonté caoutchouteuse.

L’alignement est encore assez important aujourd’hui. Certains processeurs (la famille des 68k saute aux yeux) lançaient une exception si vous tentiez d’accéder à une valeur de mot sur une limite impaire. Aujourd’hui, la plupart des processeurs exécutent deux cycles de mémoire pour extraire un mot non aligné, mais ce sera certainement plus lent qu’une extraction alignée. Certains processeurs ne lèveront même pas une exception, mais récupéreront une valeur incorrecte de la mémoire!

Si ce n’est rien d’autre que des performances, il est sage d’essayer de suivre les préférences d’alignement de votre processeur. Habituellement, votre compilateur se chargera de tous les détails, mais si vous faites vous-même quelque chose pour structurer la mémoire, cela vaut la peine d’être pris en compte.

Vous devez toujours être conscient des problèmes d’alignement lors de la mise en place d’une classe ou d’une structure en C (++). Dans ces cas, le compilateur fera le bon choix pour vous, mais la taille globale de la structure / classe peut être plus inutile que nécessaire.

Par exemple:

 struct { char A; int B; char C; int D; }; 

Aurait une taille de 4 * 4 = 16 octets (supposons Windows sur x86) alors que

 struct { char A; char C; int B; int D; }; 

Aurait une taille de 4 * 3 = 12 octets.

Cela est dû au fait que le compilateur applique un alignement de 4 octets pour les entiers, mais seulement 1 octet pour les caractères.

En général, regroupez les variables de membre de même taille (type) pour minimiser l’espace perdu.

Comme Greg l’a mentionné, cela est toujours important aujourd’hui (peut-être davantage à certains égards) et les compilateurs s’occupent généralement de l’alignement en fonction de la cible de l’architecture. Dans les environnements gérés, le compilateur JIT peut optimiser l’alignement en fonction de l’architecture d’exécution.

Vous pouvez voir des directives pragma (en C / C ++) qui modifient l’alignement. Ceci ne devrait être utilisé que lorsqu’un alignement très spécifique est requirejs.

 // For example, this changes the pack to 2 byte alignment. #pragma pack(2) 

Notez que même sur les IA-32 et AMD64, certaines instructions / informations insortingnsèques de SSE nécessitent des données alignées. Ces instructions renverront une exception si les données ne sont pas alignées. Ainsi, vous ne devrez pas au moins déboguer les bogues “données incorrectes”. Il existe également des instructions équivalentes non alignées, mais comme le dit Denton, elles sont plus lentes.

Si vous utilisez VC ++, outre les directives #pragma pack, vous disposez également des directives __declspec (align) pour un alignement précis. La documentation VC ++ mentionne également une fonction __aligned_malloc pour des exigences d’alignement spécifiques.

En règle générale, vous pouvez probablement ignorer les problèmes d’alignement, sauf si vous déplacez des données entre compilateurs / langues ou utilisez les instructions SSE.