← SEARCHABLE ARCHIVE
Computer Science · 2026-05-13

¿Qué es la alineación de la memoria?

¿Por qué el tamaño de la memoria es diferente aunque tenga la misma estructura?

INTERACTIVE READING MODE →

Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.

Mientras codifica, hay ocasiones en las que el tamaño de la estructura es diferente de lo que esperaba. Este fenómeno se llama oficialmente Alineación y relleno de memoria.

Cuando la CPU lee variables de la memoria, no las lee en unidades de 1 byte. Debido a que se lee en fragmentos, palabra por palabra (generalmente 4 bytes u 8 bytes), la forma en que se organizan las variables en la memoria es extremadamente importante para el rendimiento.

El tamaño total de la estructura puede variar dependiendo de cómo estén dispuestos los miembros de la estructura en la memoria. Esto se debe al concepto de relleno. El relleno es un espacio vacío que el compilador inserta automáticamente para ayudar a alinear los miembros de una estructura con los límites de las palabras en la CPU. Como hay un espacio vacío en el medio, el tamaño de la estructura aumenta naturalmente.

Comprobémoslo nosotros mismos con el código.

#include <iostream>
#include <cstddef> //Usando la macro offsetof

//1. Ubicación de memoria ineficiente (24 bytes en total)
struct BadOrder {
    int A;       //4 bytes, la siguiente variable requiere una alineación de 8 bytes, lo que da como resultado 4 bytes de relleno (usando un total de 8 bytes).
    long long B; //8 Bytes, 8 Bytes usados ​​solos. (Se utilizaron un total de 16 bytes)
    bool C;      //El relleno de 1 byte y 7 bytes se produce después de utilizar 1 byte (se utilizan un total de 24 bytes).
};

//2. Ubicación eficiente de la memoria considerando la optimización del compilador (16 bytes en total)
struct GoodOrder {
    long long A; //8 Bytes, 8 Bytes usados ​​solos. (Se utilizaron un total de 8 bytes)
    int B;       //4 bytes, las siguientes variables se pueden utilizar en los 4 bytes restantes, por lo que no se produce relleno. (Se utilizaron un total de 12 bytes)
    bool C;      //El relleno de 1 byte y 3 bytes se produce después de utilizar 1 byte. (Se utilizaron un total de 16 bytes)
};

//3. Estructura con relleno eliminado a la fuerza (total 13 bytes)
#pragma pack(push, 1)
struct PackedStruct {
    int A;       // 4 Byte
    long long B; // 8 Byte
    bool C;      // 1 Byte
};
#pragma pack(pop)

Aquí surge una pregunta. ¿Por qué hay 7 bytes de relleno adicionales al final de BadOrder y 3 bytes de relleno al final de GoodOrder? Esto se debe a los requisitos de alineación cuando las estructuras se agrupan en matrices, etc. El tamaño total de la estructura debe ser un múltiplo del tipo de datos más grande (8 bytes de longitud en el ejemplo anterior) entre los miembros internos. Esto se debe a que se puede garantizar la misma alineación de 8 bytes al pasar al siguiente elemento de la matriz.

El número 3 es quitar con fuerza el relleno usando #pragma pack. Esto puede ahorrar memoria a sólo 13 bytes, pero puede causar una degradación fatal del rendimiento. Si la CPU lee palabra por palabra y el punto inicial de los datos está desalineado, La CPU tiene que leer la memoria dos veces y realizar una operación adicional inútil para forzar su fusión. En ciertos entornos de hardware, el programa puede incluso fallar.

Además, no se puede ignorar la eficiencia de la línea de caché. Las CPU modernas suelen importar toda la memoria en unidades de 64 bytes, pero si son 24 bytes como en el número 1, solo se pueden almacenar 2 en 64 bytes. Si lo optimiza a 16 bytes como en el número 2, los 4 encajarán perfectamente. Al realizar un bucle en una matriz, existe una gran diferencia en la velocidad de procesamiento.

A menos que existan casos especiales en los que el diseño de la memoria deba ser preciso sin errores de 1 byte, como estándares de comunicación de red o entrada/salida de archivos, En situaciones generales, permitir el relleno tiene mayores beneficios de rendimiento. Por lo tanto, es una buena idea adquirir el hábito de minimizar el relleno innecesario agrupando los miembros comenzando con el tamaño más grande (o en orden inverso), como se muestra en el número 2.