preface

Align was mentioned in the previous article in the object Alloc process exploration, so why align and how do programs align? Next we go to research

What is memory alignment?

Let’s start with the following example:

struct struct0 {
    int a;  
    char c;
}s;

NSLog(@"s : %lu".sizeof(s)); / / output 8
Copy the code

Int = 4byte, char = 1byte, int = 4byte, char = 1byte, int = 4byte, char = 1byte, int = 4byte, char = 1byte

The elements are placed in memory one by one in the order they are defined, but they are not tightly packed. Starting from the first address of the structure’s storage, each element when placed in memory will think that memory is divided by its size (usually it is 4 or 8), so the element must be placed at an integer multiple of its width. This is called memory alignment

Why memory alignment?

1. Platform limitations

  • Hardware platforms differ greatly in how they handle storage space. Some platforms can only access certain types of data from certain addresses, and it usually starts withDouble bytes, four bytes, eight bytes,16 bytes and even 32 bytesTo access memory in units.

2. Performance reasons

  • For example, in32 -Under theintIf it’s aligned, it can be read once. If it’s not aligned,intIf it is stored in an odd digit or not in a multiple of 4, it needs to be read twice and then spliced to get the data.
    • For example, there is no memory alignment mechanism, oneintVariable secondary address1Start the storage, as shown below:

In this case, the processor needs to:Weed outAgain,mergeI went to the register and did some extra operations. And in theMemory alignmentCan be read out in one go,Improved efficiency.

Three, memory alignment rules

1. The concept:

  • Each platform-specific compiler has its own defaultCoefficient of alignment,(Also called alignment modulus). This can be done by precompiling commands#pragma pack(n), n = 1,2,4,8,16To change this coefficient, this onenThat’s what we have to work outCoefficient of alignment,.
  • Valid alignment valueThe given value:#pragma pack(n)And the longest data type length in the structuresmallerThe most.Valid alignment valueAlso calledAlign the unit.
  • XcodeThe default#pragma pack(8), that is,8-byte alignment.

2. The rules:

  • (1): structureThe offset of the first member is 0, the offset of each member relative to the first address of the structureAre integer multiples of the smaller of the member size and the valid alignment valueIf necessary, the compiler will add between membersPadding bytes.
  • (2): The total size of the structure isAn integer multiple of the valid alignment valueThe compiler will add it after the last member if necessaryPadding bytes.

3. For example:

The structure of the body

Environment: (Xcode 12.3)

struct Struct1 {
    double a;
    char b;
    int c;
    short d;
}s1;
Copy the code

Analysis:

  • The alignment coefficient is:pack(8), that is,8 bytes, the longest data type is:double, and it is also8 bytes,Valid alignment value:Min (8, 8) = 8
  • According to theRule (1) (2), it can be concluded:

The size of each member should be compared to the valid alignment value, taking a smaller number, and then an integer multiple of this number as the starting position for the offset of the member variable. If the middle is not an integer multiple, then the bytes need to be filled. After the member variable is stored, if the overall size is not an integer multiple of the effectively aligned value, you need to fill the bytes at the end until the overall size is an integer multiple of the effectively aligned value.

The result of the analysis is 24 bytes, let’s print it to verify:

The printed result is the same as our analysis ~

Example 2:

struct Struct2 {
    double a;       
    int b;          
    char c;         
    short d;        
}s2;

printf("\n Struct1 size: %lu\n".sizeof(s2));  16 / / output
Copy the code

The member variables of the two structures are the same, but the location is changed, and the memory size is changed. This…

Let’s continue the analysis:

The result of the analysis is16 bytes, let’s print and verify:

Original structureOrder of member variablesThere is also an impact on memory

Example 3:

struct Struct3 {
    double a;           // 8 [0,7]
    int b;              // 4 [8,11]
    char c;             / / 1 [12]
    short d;            // 2 (13, [14,15])
    int e;              / / 4 [16, 19]
    struct Struct1 {
        double a;       // 8 (20, 21, 22, 23, [24, 31]
        char b;         / / 1 [32]
        int c;          // 4 (33, 34, 35 [36, 39])
        short d;        // 2 [40, 41], 42, 43, 44, 45, 46, 47, 48
    }s1;
}s3;
Copy the code

Analysis:

  • The alignment coefficient is:pack(8) = 8.Struct1One of the most great8 bytes.Struct3The other members are the largest8 bytes,Struct3 Valid alignment value:min(pack(8),8) = 8

Print verify:



The result is correct

Possible misunderstandings
  1. offset: To compute membersoffset, it is possible to treat an integer multiple of the size of the member as itsoffsetThis is wrong.offsetIs made up ofValid alignment valueandMembers of the sizeInteger multiples of the minimum of the two values
  2. The overall size: The overall size (replenished bytes if needed) is an integer multiple of the largest member, which is inaccurate. The overall size isValid alignment valueThe integer times of

Here’s an example:

Under the 32-bit

// Pack (4)
struct Struct4 {
    int a;           // 4 [0,3]
    double b;        // 8 [4,11]
}s4;

printf("\n\n Struct4 size: %lu\n".sizeof(s4));  / / output 12
Copy the code

Under a 64 – bit

// Pack (8)
struct Struct4 {
    int a;           // 4 [0,3]
    double b;        // 8 (4, 5, 6, 7, [8, 15]
}s4;

printf("\n\n Struct4 size: %lu\n".sizeof(s4));  16 / / output
Copy the code

Print as follows:

  • in32 –,Struct4theValid alignment valueismin(pack(4), 8) = 4.aFrom the initial address,btheoffsetismin( min(pack(4), 8), 8) = 4, so the result is12

  • inA 64 – bit,Struct4theValid alignment valueismin(pack(8), 8) = 8.aFrom the initial address,btheoffsetismin( min(pack(8), 8), 8) = 8, so the result is16
conclusion
  • Compute memberoffsetIs made up ofValid alignment valueandMembers of the sizeInteger multiples of the minimum of the two values.
  • The overall size (after the addition, if needed) isValid alignment valueInteger multiple of.
  • Of or relating to a member of a structureDifferent order results in different memoryThe essence of an object is a structure that we can adjustThe location of an object propertyTo optimize the memory.

object

How to get the memory size of an object
  • sizeof
  • class_getInstanceSize
  • malloc_size
sizeof
  1. sizeofOperator, not a function
  2. sizeofI’m passing in the type to figure out how much memory this type has. This is inCompiler compile phaseIt will determine the size and convert directly to8, 16, 24Constant like this, andNot computed at run time. The parameter could beArray, pointer, type, object, structure, functionAnd so on.
  3. Its function is to obtain the size in bytes that is guaranteed to hold the maximum object created by the implementation
class_getInstanceSize
  • class_getInstanceSizeisruntimeTo provide theapi, compute objectActual memory size, the use of8-byte alignmentIn the same way.
malloc_size
  • malloc_sizeUsed toCalculates the actual memory size allocated by the objectThis is by the systemUse 16-byte alignmentIn the same way

You can pass the following code test:

@interface LGPerson : NSObject

@property (nonatomic.copy) NSString *name;
@property (nonatomic.copy) NSString *nickName;
@property (nonatomic.assign) int age;
@property (nonatomic.assign) long height;

@end
// LGPerson has 4 properties NSString *name, NSString *nickName, int age, long height
int main(int argc, const char * argv[]) {
    LGPerson *person = [LGPerson alloc];
    person.name      = @"Cc";
    person.nickName  = @"KC";

    NSLog(@"\n%lu\n - %lu\n - %lu\n".sizeof(person), class_getInstanceSize([LGPerson class]), malloc_size((__bridge const void *)(person)));
    // Output 8, 40, 48
    return 0;
}
Copy the code