What is memory alignment

Memory alignment, also known as byte alignment.

Memory space in the modern computers are divided according to the byte, theoretically seems to access to any type of variables can be starting address, but the reality is when they visit a specific type variables are often in a particular memory address access, which requires all kinds of data according to certain rules in space arrangement, rather than order one after the other, That’s alignment.

To take a simple example,64A system,intThe memory space occupied is4 bytes.charfor1 byte. If they were placed in a structure, the amount of memory they would take up would be4 + 1 = 5 bytes. And in fact, inXcodeThe environment,sizeofThe result of the operation is8 bytes:

Why memory alignment

There are two reasons for memory alignment:

Platform cause: Storage space is treated differently by different hardware platforms. Some platforms can only access certain types of data from certain locations. For example, in architectures where the CPU has an error accessing an unaligned variable, the program must ensure byte alignment.

Performance reason: Memory alignment improves access efficiency. For example, some platforms start each read at an even address. If an int is stored at the beginning of an even address, one read cycle will cover 32 bits. If an int is stored at the beginning of an odd address, two read cycles will be required. The 32bit data can be obtained by piecing together the high and low bytes of the result of the two readings.

Three, the principle of memory alignment

1. Data member alignment rules: The data member of a struct (or union), the first data member is placed at offset 0, and the starting position of each data member is from the size of the member or the size of the member’s children (as long as the member has children, such as arrays). Structure, etc.) (for example, if an int is 4 bytes on a 32-bit machine, it will be stored from a multiple of 4, or if a short is 2 bytes on a 32-bit machine, it will be stored from a multiple of 2).

2. Struct as members: If a struct has members, then the members are stored from an integer multiple of the size of the largest element in the struct.

3. Finishing off: the total sizeof a structure, the result of sizeof, must be an integer multiple of its largest internal member. What is lacking must be made up.

Byte table

Fourth, memory alignment bottom exploration

Why explore internal alignment of structures in the first place? When we create objects, we don’t need to pay attention to the order of attributes, because the system will automatically deal with it for us. But when we create structures, we need to analyze them, because the system will not automatically optimize for us.

Let’s look at the following two structures (no nesting)

struct LGStruct1{
    double  a; // 8
    int     b; // 4
    short   c; // 2
    char    d; // 1
}LGStruct1;


struct LGStruct2{
    double  a; // 8
    char    d; // 1
    int     b; // 4
    short   c; // 2

}LGStruct2;
Copy the code

We declare that the two structures have the same types of data and should in theory have the same size of memory. Then take a look at the following code

-- -- -- -- -- -- -- -- -- 16-24Copy the code

Why does the same data type have the same number of attributes, but occupy different space sizes? That’s the focus of today, the principle of internal alignment of structures (number 3 above)

(min(m, n) m represents the current starting position, and n represents the size) variable A: 8 bytes, offert starts from 0, min(0, 8), that is, 0 ~ 7 stores variable A b: C: takes up 2 bytes. Offert starts from 12 (12 can be divisible into 2). Min (12, 2), that is, 12 ~ 13 stores c variable D: In 1 byte, offert starts at 14 (14 divisible into 1), min(14, 1), that is, 14 stores d\

The result shows that the actual memory size of LGStruct1 is 15 bytes, and the largest variable in LGStruct1 is a, which is 8 bytes. So the actual memory size of LGStruct1 must be an integer multiple of 8. 15 is not an integer multiple of 8. Finally, the memory size of LWStruct1 is 16 bytes.

LGStruct1 parsing is shown below

LGStruct2 memory size detail process variable A: 8 bytes, offert from 0, min(0, 8), that is, 0 ~ 7 store A. Variable D: occupies 1 byte, offert starts from 8 (8 can be divisible into 1), min(8, 1), that is, 8 stores D. Variable B: takes 4 bytes, offert starts from 9 (9 cannot be divisible into 4), min(9, 4), 9%4! = 0, keep moving back until you find a place where 4 is divisible 12, which is 12 to 15 for B. Variable C: takes 2 bytes, offert starts from 16 (16 can be divisible into 2), min(16, 2), that is, 16 ~ 17 stores C.

The result shows that the actual memory size of LGStruct2 is 18 bytes, and the largest variable in LGStruct2 is a, which is 8 bytes. So the actual memory size of LGStruct2 must be an integer multiple of 8, 18 is not an integer multiple of 8, rounded up, less than 24 bytes autocomplete. Finally LGStruct2 has a memory size of 24 bytes.

LGStruct2 parsing is shown below

A nested structure within a structure

struct LGStruct1{
    double  a; // 8
    int     b; // 4
    short   c; // 2
    char    d; // 1
}LGStruct1;


struct LGStruct2{
    double  a; // 8
    char    d; // 1
    int     b; // 4
    short   c; // 2
 
}LGStruct2;

struct LGStruct3{
    long    a; // 8
    int     b; // 4
    short   c; // 2
    char    d; // 1
    struct LGStruct2 lwStr;
}LGStruct3;

int main(int argc, char * argv[]) {
    @autoreleasepool {
      NSLog(@"-----%lu-----%lu----%lu",sizeof(LGStruct1),sizeof(LGStruct2),sizeof(LGStruct3));
    }
    return 0;
}
Copy the code

Printed result

-- -- -- -- -- -- -- -- -- 16-24 to 40Copy the code

LGStruct3 memory size detailed process

Variable A: 8 bytes, offert starts from 0, min(0, 8), that is, 0-7 stores variable A b: 4 bytes, offert starts from 8 (8 can be divisible into 4), min(8, 4), that is, 8-11 stores variable B C: It takes up 2 bytes, offert starts from 12 (12 can be divisible into 2), min(12, 2), that is, 12 ~ 13 stores the c variable D: takes up 1 byte, offert starts from 14 (14 can be divisible into 1), min(14, 1), that is, 14 stores D \

Variable lwStr:lwStr is a structure variable. The structure members are stored from an integer multiple of their internal largest element size. The largest variable in LGStruct2 is 8 bytes, so offert starts at 16 and LGStruct2 has a memory size of 18 bytes. Min (16,18), namely, 18-33 store lwStr

The result shows that the actual memory size of LGStruct3 is 34 bytes, and the largest variables in LGStruct3 are lwStr and a are both 8 bytes. So the actual memory size of LGStruct3 must be an integer multiple of 8, 34 is not an integer multiple of 8, rounded up, less than 40 bytes autocomplete. Finally, LGStruct3 has a memory size of 40 bytes.

LGSTruct3 parsing diagram is shown below

Five, the summary

1. Simple structure: The first data member is stored at offset 0, and the starting position of each data member is stored at an integer multiple of the size of the member. 2. Structure with nested structure: the nested structure members are stored from an integer multiple of the size of the largest internal element. 3. The total size of the structure must be an integer multiple of the size of the largest internal member.

Memory alignment has a set of rules designed to improve CPU access efficiency and secure access. Byte alignment may be a waste of memory, but memory optimization minimizes memory waste as much as possible, ensuring access speed and reducing memory waste, which is really good.