We explored the initialization process of OC objects in the previous article, but what factors are involved in the size of an object? Or what factors determine how much memory an object needs to open up? Let’s explore it here.

Factors that affect the size of an object’s memory

So once again let’s look at an example. First declare an empty object. We print the memory size of the object type, the actual memory size, and the system memory size.

Case 1

In case 1, we can see that the memory size of the object type is 8 bytes (p is the pointer type), but the actual memory size and system memory size is 0.

Case 2

Now if we print again, we can see that the memory size of the object type is 8 bytes, the actual memory size is 8 bytes, and the actual memory size is 16 bytes. So why did alloc init change the actual memory and open memory to 8 bytes and 16 bytes, respectively? The actual memory footprint here is 8 bytes because NSobject has an isa property, and isa isa pointer type.

Case 3

@interface LGPerson : NSObject

- (void)test1;

+ (void)test2;

@end

@implementation LGPerson

- (void)test1 {
    NSLog(@"test1");
}

+ (void)test2 {
    NSLog(@"test2");
}

@end

Copy the code

Here we add a class method and an instance method to LGPerson, and when we print it, we can see that the size of each item has not changed. At least one thing we can prove here is that neither the object method nor the instance method has any effect on the size of the object.

Case 4

We can see from three cases:

  • One was added in case 4.1nameProperty, because the string is 8 bytes, the actual memory of the printed object is 16 bytes, and the actual memory size is 16 bytes.
  • One was added in case 4.2ageProperty is 4 bytes, but the actual printed memory is 24 bytes, not 20, and the actual memory size is 32 bytes (an integer multiple of 16).
  • In case 4.3, a bookNum attribute was added, which was also 4 bytes, and the printing memory usage did not increase. The actual memory of the object was still 24 bytes, and the actual memory size was still 32 bytes.

Here we can see a pattern. In case 4.2 we added a 4-byte age attribute, but the actual memory was 24 bytes instead of 20 bytes, and 24 is a multiple of 8. The actual memory size is an integer multiple of 32 bytes equal to 16. The reason why the memory didn’t change in case 3 is because 20 plus 4 is still 24, which is 3 times 8. It is still less than 36, and the actual size of memory allocated has not increased.

So here you can find a rule, the memory size is 8 bytes integer multiples, the actual memory size is 16 bytes integer multiples. This is actually internal memory alignment. Let’s take a look at the alignment of structures.

The principle of internal alignment exists in the structure

  1. Data member alignment rules: The first data member of a struct or union is stored at offset 0, and the starting location of each data member is the size of the member or its children (as long as the member has children, such as arrays). Structure, etc.) (for example, if int is 4 bytes, it is stored from the address that is a multiple of 4).
  2. Struct as members: If a struct has some struct members, the struct members are stored from an integer multiple of their internal largest element size. (struct A contains struct B, char, int, double, etc.)
  3. The total sizeof the structure, the result of sizeof, must be an integer multiple of the largest member within the structure.

Here are a few examples to see if this alignment principle is correct.

Case 1

struct LGStruct1 { double a; char b; int c; short d; }struct1; // The first data member of the struct is placed at offset 0. Since a is of type double, a is 8 bits and stored at position 0 to 7. [0...7] // The starting position of each data member is an integer multiple of the size of the member or its children. [8] // Start with an integer multiple of the size of each member. Since int is 4 bytes, start with 12, 9, 10, 11 are empty, and c is stored between 12 and 15. [12,13,14,15] // since short is 2 bytes and 16 is a multiple of 2, d is stored in position 16 through 17 // d: [16,17] // the sizeof the struct1 must be a multiple of the sizeof the largest member in the struct1Copy the code

The size of struct1 is derived from the principle of internal alignment and is also 24 bytes by printing.

Case 2

struct LGStruct2 { double a; int b; char c; short d; }struct2; // The first data member of the struct is placed at offset 0. Since a is of type double, a is 8 bits and stored at position 0 to 7. [0...7] // The starting position of each data member is an integer multiple of the size of the member or its children. [8,9,10,11] // start with a multiple of the size of the member. Char is 1 byte and 12 is a multiple of 1. [12] // Since short is 2 bytes and 14 is a multiple of 2, d is stored at position 14 to 15 // d: [14,15] // the result of sizeof the struct must be a multiple of the largest member of the struct (a = 8 bytes), so the sizeof struct2 is 16Copy the code

Struct1 and struct2 member variables are the same, but their positions are different, which causes their final sizes to be different. Therefore, the position order of member variables also affects the size of the structure. But objects don’t, because the compiler rearranges the object’s member variables.

Case 3

struct LGStruct3 { double a; int b; char c; short d; int e; struct LGStruct1 str; }struct3; // The first data member of the struct is placed at offset 0. Since a is of type double, a is 8 bits and stored at position 0 to 7. [0...7] // The starting position of each data member is an integer multiple of the size of the member or its children. [8,9,10,11] // start with a multiple of the size of the member. Char is 1 byte and 12 is a multiple of 1. [12] // Since short is 2 bytes and 14 is a multiple of 2, d is stored at position 14 to 15 // d: [14,15] // the starting position of each data member is an integer multiple of the size of the member or its children. Since e is an int, it is stored in bits 16 to 19. [16,17,18,19] // if a structure has some structure members, the structure members are stored from an integer multiple of the size of the largest element in the structure. Because LGStruct1's largest internal element, a, is a double of 8 bytes, it needs to be stored at a multiple of 8, so it needs to be stored at 24. As we saw in case 1, LGStruct1 takes up 17 bytes, So STR is stored from 24, plus 17, which equals 41. Depending on the total size of the structure, STR must be an integer multiple of the largest internal member. Because the maximum member is 8 bytes, the final size of stuct3 is 48 bytes.Copy the code

The final print size is also 48 bytes.