So we know that the underlying alloc is to open up memory space and associate it with our class, so what does the amount of memory an object opens up have to do with it?

What are the factors that affect object memory?

Let’s start with an exampleWe define an LhkhPerson that doesn’t have any member variables, properties, or methods, and when we print out its memory size, it’s 8.When you add an NSString property, the size is 16In the end, through similar examples above,objecttheMemory sizeDepending on itattributeandMember variablesAnd what’s insidemethodsIt doesn’t matter. It boils down to impactThe object of memoryThe factor isMember variables.

We explored that object memory is related to member variables, so when we add an int again, we print out the size of the memory

Add 8 more (we know that int is 4 bytes),So why is it still increasing8 bytes?

There is internal alignment of structures

A table of the size of bytes consumed by each type

There are three principles of alignment in structure

  • Data member aligned principle: structure (struct) (or a consortium (union) data members, the first data in the offset to zero, after location of each data member from the member or members of the son members (members as long as the son of the members, such as arrays, structures, etc.) the size of the integer times;

  • Structs as members: If a struct has some struct members, then the elements in the struct members are stored from the address of an integer multiple of the maximum number of bytes that the internal elements occupy. (struct a, struct b, char, int, double) (struct a, struct b, char, int, double) (struct b, char, int, double)

  • The rule of closeout: the total sizeof a structure, the result of sizeof, must be an integer multiple of the largest member in the structure, making up any shortfall.

Here’s an example that combines these three principles:

struct LhkhStruct1 { double a; // 8 [0 7] double takes 8 bytes from 0 to 7, that is, 'a' is stored in 0-7 char b; // 1 [8] char = 1; // 1 [8] char = 1; // 1 [8] char = 1; / / 4 (9 10 11 12 13 14 15] [int is a 4 bytes, on one of the elements' b 'to eight, so "c" should be started from September, according to the' data member aligned principle 9 not 4 integer times, it will be to the rear, 10, 11 are so, 12 is 4 integer times, So the element 'C' should start at 12 and end at 15 short d; // 2 [16 17] 1 short (struct1); // 2 [16 17] 2 short (struct1); // 2 [16 17] 2 short (struct1); //24 Struct LhkhStruct2 {double a; // 8 [0 7] int b; // 4 [8 9 10 11] char c; // 1 [12] short d; // 2 (13 [14 15] }struct2; //16 Struct LhkhStruct3 {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 LhkhStruct1 str1; // Struct3 (20 21 22 23 [24...40] 41}); // Struct3 (20 21 22 23 [24...40] 41}); //48 NSLog(@"LhkhStruct1-->%ld",**sizeof**(struct1)); NSLog(@"LhkhStruct2-->%ld",**sizeof**(struct2)); NSLog(@"LhkhStruct3-->%ld",**sizeof**(struct3));Copy the code

Let’s try to explain it based on three principles:

LhkhStruct1 memory size is 24: based on the elements in the structure, we calculate that the memory size needs to be 0 to 17, that is, the size of 18, and the largest element in the structure is 8 bytes of double, so we need to take an integer multiple of 8, and 18 is not an integer multiple of 8, so we take 24;

The memory size of LhkhStruct2 is 16: according to the elements in the structure, we calculate that it needs to occupy 0 to 15, that is, the size of 16, and the largest element in the structure is 8 bytes of double, so we need to take an integer multiple of 8, and 16 is just an integer multiple of 8, so we take 16;

Here, we can notice that in fact, the variables contained in LhkhStruct1 and LhkhStruct2 are very detailed, and the order is changed, so the size of the results are not consistent, which well explains the system's optimization of the structure's internal storage alignmentCopy the code

LhkhStruct3 memory size is 48: When we calculated according to the inside of the elements in addition to the str1 take up 0-19, and we know the inside of the str1 biggest members of 8, according to the principle of 2, the str1 should start from the position of the 24, 17, from behind the 24 began namely 0-41, according to the principle 3, the biggest member for double 8, 8 and str1 So it’s going to be an integer multiple of 8, so it’s going to be 48; In fact, we can do the same thing here, we know that except for str1, it takes 0 to 19, so we need 24 according to principle 3, and we also need 24 for str1, so we can just add 24+24=48.

Let’s print and verify our calculated value:

Let’s go back and look at this example again: this is our LhkhPersonLet’s print out the memory size again:

We found that usingsizeofThe result of the print is8.class_getInstanceSizeThe result of the print is40.malloc_sizeThe result of the print is48So where did all this come from?

After understanding the principle of internal alignment of structures, let’s explain these prints again:

  • Sizeof (p) prints 8: this is because our object p is essentially a pointer to the structure, and the sizeof the pointer to the structure is 8;

  • Class_getInstanceSize (p.class) prints 40: first we need to understand that class_getInstanceSize is a calculation of the size of the member variables in the object. (name = 8, nickname = 8, age = 4, double = 8, height = 8, char = 1, so 8+8+4+8+1=29)

Two points to note:

1. Note the inheritance of the parent property and ISA, so add an 8 byte size of ISA. 2. Note the 8-byte alignment principle of member variables.Copy the code

So 29 plus 8 is 37, and then you align it with 8 bytes, so you take multiples of 8 which is 40;

  • malloc_size((__bridge const void *)p)The print result is48: First we need to knowmalloc_sizeThe method is to calculate the actual system memory space size of the object;

Need to pay attention to

1. The calculated result should be based on the memory size calculated by class_getInstanceSize; 2.16 Byte Alignment rulesCopy the code

So class_getInstanceSize calculates memory to be 40, and malloc_size calculates memory to be 48 based on the 16-byte alignment principle.

We know that sizeof is an operator, not a function, which is used to calculate the memory sizeof the data type;

Class_getInstanceSize should be familiar, as we saw when we explored the underlying alloc: by searching the objc source code, we can eventually lock into this algorithm (x + WORD_MASK) & ~WORD_MASK, which is the 8-byte alignment algorithm;

Malloc_size is a bit new to this method (I haven’t used it before, please forget I’m a little bit new). In combination with class_getInstanceSize to get the actual memory size of the variable (8 bytes aligned), this is the actual memory size allocated, and 16 bytes aligned. So how does malloc work internally?

The malloc inquiry

We explore a method, first basically all command click in to view the source code, but we found that there is no malloc_size implementation source code, bitter…

Don’t panic. We can just go to the bottom of alloc, we know thatmalloc_sizeThis way, let’s go to the next oneSymbol shorterLook at the assembly on the line,, assembly (yyds) 😊

In fact, by looking at the path of the malloc.h file above, we found that it is already under the file usr/include/malloc, we should guess that the source code should be in the system’s malloc library, so we can directly drive the apple opensource library opensource/ this is the express train. We are using libmalloc 317.40.8 source code as an example:

So we have a question to discuss, in front of us through the above example to get the actual variable memory size is 40, why the system finally allocated memory is 48? (Although we already know this is due to the 16-byte alignment of objects in the heap) let’s go to ——>

Malloc source code compilation

When we talked about alloc we knew that calloc was the system’s way of opening up memory, so let’s talk about malloc_size and start with calloc;

Create 40 bytes of memory by calling the calloc method, and then explore how much memory the system eventually allocates:

commandClick on thecallocEntering the method implementation, we find that it is called internally_malloc_zone_calloc

commandClick on the_malloc_zone_callocEnter the method implementation

We go intocallocMethod, and found that only a method declaration, and no implementation…This is when we found out by searching for Calloc

Then we willpothezone->calloc

And we found outzone->callocIt’s storing this methoddefault_zone_callocSo let’s do a searchdefault_zone_calloc

And then I found outnano_callocSo let’s do a searchnano_calloc

Continue into_nano_malloc_check_clearThrough analysis, it is found that the memory related issize_t, see the method behindsegregated_size_to_fit Follow up, familiar flavor –>16-byte alignment

After the above exploration we should finally be able to get

  • The heap object memory is16-byte alignment
  • The member variables inside an object are8-byte alignment
  • Between objects16-byte alignment