2017-08-31 6 views

Répondre

1

Ce sont deux facteurs indépendants: size dicte la taille brute, align est simplement le placement du bloc alloué. Dans le code réel, vous pourriez voir une corrélation, la raison pour laquelle vous voulez quelque chose d'aligné est généralement parce que size est un multiple pair d'un certain facteur, mais ce n'est pas une exigence difficile.

Vous pouvez avoir une raison parfaitement valable pour l'allocation de 79 octets alignés sur une base de 8 octets.

+0

Une référence pour cela? –

+0

Étant donné l'importance du comportement indéfini, il est toujours mentionné lorsque cela est pertinent (par exemple les pointeurs invalidants), et il n'y a aucune raison de croire que le comportement indéfini est un facteur ici. Ceci est juste un allocateur, rien d'extraordinaire. Si vous voulez allouer quelque chose de vraiment bizarre, ce comportement n'est pas indéfini, mais cela pourrait conduire à un comportement indéfini si vous y mettez une structure mal alignée. – tadman

1

La documentation d'Intel pour _mm_mallocin their own compiler indique seulement que "cette contrainte [align] doit être une puissance de deux." Il n'est pas obligatoire que la taille soit un multiple d'alignement, car le principal cas d'utilisation est SIMD, où il est tout à fait normal d'allouer un tableau avec un alignement supérieur à la largeur d'un seul membre. (par exemple, un float* aligné sur 32B pour AVX). Ou pour les limites de ligne de cache/page/énorme. par exemple. Pour tirer le meilleur parti des énormes pages transparentes, vous pouvez allouer 2 Mo d'alignement pour toute allocation supérieure à 2 Mo.

Le seul allocateur Alignés Je suis au courant de ce fait ont la limitation que vous êtes inquiet au sujet est C11/C++17 aligned_alloc, qui est malheureusement nécessaire à l'échec quand size % align != 0. Voir ma réponse sur How to solve the 32-byte-alignment issue for AVX load/store operations?. TL; DR: l'original C11 aligned_alloc était UB avec des tailles non multiples d'alignement, donc les implémentations réelles ont choisi de le faire fonctionner comme prévu comme d'autres allocateurs alignés (par exemple posix_memalign). Mais alors il a été changé pour requis pour échouer (retourner une erreur) dans ce cas, au lieu de UB, donc les implémentations qui lui ont permis de fonctionner violent techniquement une norme (stupide). C++ 17 a la version requise pour l'échec.

De toute évidence, Intel n'a pas fait la même erreur que le comité de normalisation a fait avec aligned_alloc, car il serait contraire à l'objectif de _mm_malloc pour l'optimisation. Bien sûr, ils avaient à l'esprit les cas d'utilisation SIMD et de limites de mémoire. (IDK comment le comité de normes n'a pas, semble tout à fait évident comme le cas d'utilisation principal pour les types/tampons avec plus d'alignement que l'alignement naturel du type le plus large.Il est vraiment décevant que la fonction avec la plus belle API n'est pas sûre à utiliser. (aligned_alloc retours libérables mémoire avec free et ne contrecarrent pas l'optimisation en prenant l'adresse du pointeur en entrée comme posix_memalign (ce qui conduit à des compilateurs inquiétants au sujet aliasing).)

Ou bien allouer le nombre d'octets qui est le plus grand multiple d'alignement suivant?

Cela pourrait être effectivement vrai pour les petits alignements comme 32B ou 64B. En fonction de l'implémentation, il se peut que l'espace disponible à la fin ne soit pas disponible pour les allocations plus petites avec malloc ou avec des appels de plus faible alignement à _mm_malloc. Il est prudent de lire la limite d'alignement sans faille (si elle est inférieure à une page de 4 Ko), mais n'écrivez pas dessus si vous ne l'avez pas explicitement alloué.

Dans toute implémentation de bonne qualité, il est extrêmement improbable qu'un grand alignement gâche plusieurs pages entières. Vous pouvez toujours tester en faisant de nombreuses allocations avec des alignements énormes (comme _mm_malloc(3M, 2M)) et certaines allocations qui pourraient utiliser cet espace (comme _mm_malloc(512k, 4k)), puis sleep(100). Regardez l'empreinte mémoire de votre processus avant qu'il ne se termine.