Alignement en mémoire
# Alignement en mémoire

En informatique, les contraintes d'alignement en mémoire limitent à certains multiples d'adresse mémoire, où certaines données et instructions machine peuvent être enregistrées. En outre, les optimisations d'alignement mémoire permettent d'influencer la vitesse d'exécution d'un programme uniquement en choisissant bien les adresses.

## Principe

Pour augmenter leurs performances, les processeurs sont souvent reliés à la mémoire vive par un bus de données plus large que la granularité de leur adressage : par exemple un processeur est capable d'adresser individuellement des octets (8 bits), relié à la mémoire par un bus de 4 octets (32 bits). Si une donnée de 4 octets ne se trouve pas à une adresse divisible par 4, alors, selon le modèle de processeur, il y a :

* violation de contrainte : une erreur d'alignement interrompt l'exécution des instructions ;
* alignement non optimal : deux fois 4 octets bien alignés sont lus, puis les 4 octets mal alignés sont extraits de ces 8 octets, ce qui prend bien plus de temps que lire 4 octets bien alignés.

La règle généralement applicable pour qu'une donnée soit bien alignée, est qu'elle se trouve à une adresse divisible par sa taille. Ainsi, une donnée occupant un seul octet est toujours bien alignée, une donnée de deux octets est bien alignée si elle est à une adresse paire, une donnée de 4 octets est bien alignée si elle est à une adresse divisible par 4, etc. Toutefois, la contrainte d'alignement n'excède pas le matériel sous-jacent.

Les contraintes d'alignement en mémoire dépendent de l'architecture du processeur. L'optimisation de l'alignement est plus subtil, car il peut dépendre de la mémoire cache du processeur, de la pagination de la mémoire virtuelle, et autres caractéristiques de l'accès à la mémoire. Certains compilateurs permettent d'influencer l'alignement des données.

## Pratique

### Instructions

Les processeurs RISC n'ont généralement qu'une seule taille d'instruction machine, et ces instructions doivent être bien alignées. En revanche, les processeurs CISC ont des instructions de tailles variables. Il peut donc parfois être bénéfique pour les performances d'insérer une opération sans effet (souvent appelée nop) afin que les instructions suivantes soient mieux alignées.

### Données

Lorsque des données de tailles différentes sont enregistrées en mémoire les unes à la suite des autres, il peut être utile, voire nécessaire, de laisser des trous entre elles afin qu'elles soient toutes bien alignées. Cela s'observe notamment sur la pile d'exécution et dans les types de donnée composés.

**Type de donnée composé en C**

Soient deux types de donnée composés en langage C en considérant un matériel disposant d'un bus d'adressage de 64 bits (8 octets) :

Les deux structures contiennent les mêmes membres. On pourrait donc en déduire qu'elles ont la même taille. Ainsi, en faisant l'hypothèse que :

* le type char fait 1 octet ;
* le type int fait 4 octets ;
* le type double fait 8 octets.

la taille totale serait de 1 + 8 + 4 + 3 × 1 = 16 octets.

Or si l'on affiche la taille avec l'instruction printf("%zu %zu\n", sizeof(struct no_align), sizeof(struct align)); on a de bonnes chances d'obtenir 24 et 16 octets. En effet les membres de la structure align sont bien alignés, mais pas ceux de no_align. Le compilateur rajoute des octets de remplissage (padding en anglais) pour respecter l'alignement. Une fois compilé, no_align ressemble à ceci :

On remarque que __pad1 permet à d de débuter à une adresse multiple de 8, et __pad2 complète la structure pour atteindre 24, un multiple de 8.

### Options de compilation

Avec GCC, l'option -Wpadded permet de savoir si une structure nécessite du padding pour être alignée. Voici les messages obtenus lors de la compilation de struct no_align :

