1. Internal alignment of structures
1. Ask questions
Consider the sizeof two structures:
The following two structures, only the member location is different, the memory size is the same?
struct LGStruct1 { double a; // 8 bytes char b; // 1 byte int c; // 4 bytes short d; // 2 bytes}struct1; struct LGStruct2 { double a; // 8 bytes int b; // 4 bytes char c; // 1 byte short d; // 2 bytes}struct2; NSLog(@"struct1 sizeof = %lu; struct2 sizeof = %lu",sizeof(struct1),sizeof(struct2));Copy the code
The results of
struct1 sizeof = 24; struct2 sizeof = 16
Copy the code
2. View the rules
2.1 Structure memory alignment principle
1: data member of a struct (or union), the first data member is placed at offset 0.
2: From now on, the starting location of each data member must be an integer multiple of the size of the member or its children (as long as the member has children, such as arrays, structures, etc.). (for example, if int is 4 bytes, it is stored from the multiple of 4.)
Alignment values are followed by the smaller of the value and structure (or combination) maximum data member length specified by #pragma Pack.Copy the code
3: If nested, the nested structure is aligned to an integer multiple of its own largest aligned number (the largest aligned number in child members).
4: close work: the total sizeof the structure, the result of sizeof, is an integer multiple of the largest aligned number (each member variable has its own aligned number). What is lacking must be made up.
2.2. Memory Usage diagram
3. Analyze the previous problem
According to the memory alignment principle and memory footprint diagram, we can analyze why the two structures occupy 24 and 16 memory respectively
Struct LGStruct1 {// Double a; // 8 bytes [0 7] // b to start with 8 times 1 char b; // 1 byte [8] // the starting position of c is 12 times 4 int c; // 4 bytes (9 10 11 [12 13 14 15] // the starting position of d should start from 16 times 2 short d; The total sizeof a structure must be a multiple of the sizeof the largest member within the structure. // sizeof = 24}struct1; struct LGStruct2 { double a; // 8 bytes [0 7] int b; // 4 bytes [8 9 10 11] char c; [12] short d; The total sizeof a structure must be a multiple of the largest internal member of the structure according to the memory alignment principle. // sizeof = 16}struct2;Copy the code
After analyzing the above two results, do another exercise:
struct LGStruct3 { double a; // 8 [0 7] int b; // 4 [8 9 10 11] char c; // 1 [12] short d; // 2 (13 [14 15] int e; // 4 [16,17,18,19] struct LGStruct1 STR; // 24 [24,....47] // 48 is an integer multiple of the sizeof LGStruct1 double so sizeof = 48}struct3; NSLog(@"struct3 sizeof = %lu",sizeof(struct3));Copy the code
Struct3 sizeof = 48Copy the code
4. Influencing factors of memory alignment rules
If we run the same example on a processor with a different architecture, we may get different results, and even different compiler configurations may affect this result. What are the factors that affect memory alignment rules?
4.1. Alignment coefficient
1. Set alignment coefficients with the precompiled command #pragma pack(n).Copy the code
Each compiler on a particular platform has its own default “alignment coefficient” (also known as the alignment modulus). Programmers can change this by precompiling the command #pragma pack(n), n=1,2,4,8,16, where n is the “alignment factor” you want to specify. This is an upper bound and affects only members whose alignment unit is greater than n, not members whose alignment bytes are not greater than n.
The processor can be thought of as reading/writing n bytes from memory at a time. For members of size less than n, align them according to their own alignment conditions, because they can be taken out at once no matter how they are placed. For members whose alignment criteria are greater than n bytes, alignment by its own alignment criteria takes the same number of reads as alignment by n bytes, but alignment by n bytes saves space.
Or you could write it as
#pragma pack(push,n)
#pragma pack(pop)
Copy the code
eg:
Struct LGStruct1 {double a; // 8 bytes char b; // 1 byte int c; // 4 bytes short d; // 2 bytes}struct1; struct LGStruct2 { double a; // 8 bytes int b; // 4 bytes char c; // 1 byte short d; // 2 bytes}struct2; #pragma pack() // Remove 1 byte alignment, restore default NSLog(@"struct1 sizeof = %lu; struct2 sizeof = %lu",sizeof(struct1),sizeof(struct2));Copy the code
The result is:
struct1 sizeof = 15; struct2 sizeof = 15
Copy the code
Class object memory alignment
1, problem,
@interface LGPerson : NSObject @property (nonatomic) double a; // 8 @property (nonatomic, assign) int b; // 4 @property (nonatomic) char c; // 1 @property (nonatomic) short d; // 2 @implementation LGPerson @end NSLog(@implementation) %lu", class_getInstanceSize([person class]), malloc_size((__bridge const void *)(person)));Copy the code
The person memory size is set to 24Copy the code
Question to consider:
1, LGPerson object attributes are the same as the above struct2 data member, why struct2 memory size is 16, while person memory size and struct1 size 24 are the same.
2. Why is person’s memory size 24 and the system’s memory size 32
2, analysis,
First, the object has more ISA Pointers than the structure, accounting for 8 bytes
2. Memory alignment is adopted in memory, and Apple will conduct attribute rearrangement to optimize memory;
3, class_getInstanceSize: use 8-byte alignment, referring to the size of the object attribute memory; Malloc_size: Using 16-byte alignment, the actual memory size allocated by the object must be an integer multiple of 16, referring to the memory size of the entire object.
2.1 source code analysis instanceSize 8-byte alignment
In the previous section alloc exploration we saw three core ways that alloc creates space
CLS ->instanceSize: calculates memory size 8 bytes align (ID)calloc(1, size) : opens memory, returns address pointer obj->initInstanceIsa: initializes pointer, associated with classCopy the code
instanceSize
uint32_t alignedInstanceSize() const { return word_align(unalignedInstanceSize()); / / 8 byte alignment} the inline size_t instanceSize (size_t extraBytes) const {the if (fastpath (cache. HasFastInstanceSize (extraBytes))) { return cache.fastInstanceSize(extraBytes); } size_t size = alignedInstanceSize() + extraBytes; // CF requires all objects be at least 16 bytes. if (size < 16) size = 16; // The memory size must be at least 16 bytes. }Copy the code
Word_align 8 bytes align: (x + 7) & (7 = inverse)
#ifdef __LP64__ # define WORD_SHIFT 3UL # define WORD_MASK 7UL # define WORD_BITS 64 #else # define WORD_SHIFT 2UL # define WORD_MASK 3UL # define WORD_BITS 32 #endif static inline uint32_t word_align(uint32_t x) { return (x + WORD_MASK) & ~WORD_MASK; } static inline size_t word_align(size_t x) {return (x + WORD_MASK) & ~WORD_MASK; } static inline size_t align16(size_t x) {return (x + size_t(15)) & ~size_t(15); // 16 bytes aligned}Copy the code
2.2 malloc analysis
Malloc –> 16-byte alignment algorithm:
static MALLOC_INLINE size_t segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey) { size_t k, slot_bytes; if (0 == size) { size = NANO_REGIME_QUANTA_SIZE; // Historical behavior } k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta slot_bytes = k << SHIFT_NANO_QUANTUM; // multiply by power of two quanta size *pKey = k - 1; // Zero-based! / * k + 15 > > < < 4 4 assumes that size = 2 0001 0001 0000 0000 moves to the right (value: 17) 4, 0001, 0000 left four (results of 16) * / return slot_bytes; }Copy the code
Algorithm principle: K + 15 >> 4 << 4, where 4 + 4 to the right + 4 to the left is equivalent to erasing the last 4 bits, the same as K /16 * 16, is a 16-byte alignment algorithm, less than 16 becomes 0
2.3 summarize the memory alignment algorithms currently involved
8-byte memory alignment algorithm
Word_align in alloc source code analysis
There are two 16-byte memory alignment algorithms
1) Alloc source code analysis in ALIGN16:
2) Segregated_size_to_fit in malloc source analysis
Note: Reference source objC4-818.2; Libmalloc – 317.40.8;
To be improved