Alineamiento de memoria — es la colocación de datos en memoria en direcciones que son múltiplos de un cierto número de bytes, correspondiente a la arquitectura o tipo de datos. Un alineamiento correcto es crítico para el rendimiento, el correcto funcionamiento con el hardware y algunas instrucciones del procesador.
Historia del asunto.
En las computadoras antiguas, las violaciones de alineamiento provocaban fallos de hardware (bus error), y la potencia de cálculo de los procesadores era sensible a direcciones de datos no alineadas. Incluso en arquitecturas modernas, un alineamiento correcto permite el acceso a datos en un ciclo sin penalizaciones.
Problema.
Si una estructura se coloca sin considerar el alineamiento, la lectura/escritura puede ser más lenta o imposible (por ejemplo, crash en ARM o MIPS). Además, se interrumpe el funcionamiento con APIs de bajo nivel, dispositivos o la serialización de datos para su transmisión en red.
Solución.
En C++, para controlar el alineamiento existen la palabra clave alignas (C++11) y std::align, así como atributos de compilador no estándar (__attribute__((aligned(N))) en GCC/Clang, __declspec(align(N)) en MSVC).
Ejemplo de código:
struct alignas(16) MyStruct { int a; double b; char c; }; #include <iostream> #include <type_traits> int main() { std::cout << alignof(MyStruct) << std::endl; // 16 std::cout << sizeof(MyStruct) << std::endl; }
Características clave:
¿Influye el orden de declaración de los miembros de la estructura en el tamaño y alineamiento de la estructura?
Sí, el orden de los miembros determina directamente los "padding" entre ellos, lo que puede añadir bytes adicionales al tamaño de la estructura.
struct S1 { char a; int b; }; // normalmente sizeof==8 (con alineamiento de 4 bytes) struct S2 { int b; char a; }; // normalmente sizeof==8, pero a veces menos padding
¿Se puede reducir el tamaño de la estructura sin romper el alineamiento?
Sí, si agrupas los miembros grandes primero y los pequeños después. Alinear los datos de manera eficiente teniendo en cuenta el tamaño:
struct S { double d; int i; char c; }; // mejor que de forma desordenada
¿Qué sucederá si se trabaja manualmente con direcciones no alineadas a través de punteros?
El estándar C++ declara que tal comportamiento es indefinido (undefined behavior); algunas CPU pueden generar SIGBUS o similar.
Un programador implementó su propia estructura para trabajar con SIMD, sin especificar el alineamiento. Como resultado, el programa se bloquea en algunos dispositivos ARM al intentar operaciones con datos no alineados.
Pros:
Contras:
En un proyecto que trabaja con datos de video (SSE/AVX), se aplicó alignas a las estructuras del búfer, lo que permitió utilizar siempre instrucciones SIMD de manera efectiva.
Pros:
Contras: