The road of Montana is heavy and long, never give up!!
In the previous article, object initialization Exploration, you learned how to initialize an OC object and how to create object memory with 16-byte alignment. But some questions remain unanswered, such as:
LGPerson * person = [[LGPerson alloc] init];
.- the init () method
What is the function of theLGPerson * newlg = [LGPerson new];
.+ new () method
What is the function of the- Object initialization
alloc
Why did it happenobjc_alloc
? - The system will follow
16-byte alignment
So what are the factors that affect the size of memory?
OC object initialization supplement
What does -init(), +new() do? Look directly at the source code? Definitely not. In order to analyze their function, we need to know what they run process, we use the way of assembly + under symbolic breakpoints to explore!
1. – the init () analysis
In LGPerson * person = [[LGPerson alloc] init]; Add a breakpoint in this line of code and set: Debug -> Debug Workflow -> Always Show Disassembly. Run the program, and the results are as follows:
Objc_alloc_init = objc_alloc_init = objc_alloc_init
The objc_alloc_init method is still from libobjc.a. dylib, and [[LGPerson alloc] init]; The procedure is to send an init message to the object after it has been created using the callAlloc method. Here we add the init symbol breakpoint to continue running the program:
Because LGPerson doesn’t implement the -init() method, so if you look in the method, you’ll eventually find the init method for NSObject, run -[NSObject init]; Process, eventually calling the _objc_rootInit method.
Combined with source code, set breakpoints for debugging trace, process and we in the assembly + symbol breakpoint process is consistent, as shown in the following figure! The final thing returned is the object itself created by callAlloc.
Summary process: the init method is only a constructor and does not involve the initial creation of an object.
2. + new () analysis
Explore the way and -init() the same, here no longer assembly + symbol breakpoints under the process demo, directly on the source code. LGPerson * newlg = [LGPerson new]; Instead of calling +new() directly, the objc_opt_new method is executed, as shown below:
There is a judgment process like callAlloc, if initialized for the first time, hasCustomCore() will return true, as shown in the figure below, which will enter the sending message process, which will send a new message.
Because LGPerson doesn’t implement a new class method, it’s going to find NSObject in the process of finding a method, and it’s going to end up with +[NSObject new]; Methods. See the picture below:
Continuing with the program will take you to the _objc_rootAllocWithZone to initialize the object.
[[CLS alloc] init]; Process encapsulation.
Although +new() is for [[CLS alloc] init]; But [[CLS alloc] init] is still recommended; Initialize the object! Because init acts as a constructor, you can customize the initialization methods you need.
LLVM optimizes alloc
** understanding is not enough thorough, write down is also doubtful! To complement… 六四运动
Three. Object memory influence factors
As we learned in the last article, the system allocates object memory space in the form of 16-byte alignment, while the actual size of the object’s memory footprint is 8 bytes aligned.
1. Memory alignment
Memory alignment can be understood as that when the memory size of the member in the structure is applied for, the minimum memory allocation of the system is 8 bytes, which is applied for by 8 bytes each time. If the memory size is not 8 bytes, the system also applies for 8 bytes. Then, the system applies again according to the order of the member variables in the structure until all the member variables can be put down.
When the member memory of the structure is small in the front, memory will be wasted due to memory alignment. To solve this problem, Apple uses space for time, and rearranges the attributes in the class, so as to achieve the purpose of memory optimization.
2. Examples of memory factors
So what are the factors that affect object memory? Combined with the case analysis! There is a GFPerson class with two properties (NSString *) -lgName, nikeName, class_getInstanceSize(gfPerson.class) to get [at least] the memory size of the created object. As shown in the figure below:
-
Why is it 24? Because GFPerson inherits from NSObject, there’s also an 8-byte ISA that takes up space. So the minimum required memory space is 8 + 8 + 8 = 24, which is exactly 8 bytes aligned.
-
Add an int-age attribute, and the total content occupied is 32! Because 8 + 8 + 8 + 4 = 28,8 byte alignment algorithm, so the memory footprint is 32.
-
Adjust it again, add two methods, one object method, one class method, and run to find that it’s already 32. Note This method does not affect the memory usage.
-
Add a member variable double-height; 8 + 8 + 8 + 4 + 8 = 36,8 bytes aligned, so the output is 40.
To summarize:
From the above example, the factors that affect the size of an object are attributes and member variables, not methods! And as long as this property is present it will take up the space, even if it’s not initialized!
3. Memory structure parsing
In combination with the above example, GFPerson provides the following member variables and properties: Height (double), lgName(NSString *), nickName(NSString *), age(int), Score (double), CH1 (char), CH2 (CHAR), ch3(char). Where height is not initialized, run the program, print the memory structure, and the size of the object. See the picture below:
Summary:
- Because the object occupies
48 bytes
So the first six 8-byte data are when gF1 stores the contents from0x100b450e0
The address is not the beginning of gF1 data content! Age, CH1, CHA2 and CH3
The system went throughMemory optimization
.It contains 8 bytes
.Floating point Numbers
The output is required a special treatment to adoptp/f
Or,e -f f --
.
Four. Structure in vivo alignment
As an extension of the object memory analysis, let’s discuss the memory alignment of structures.
1. The principle of alignment exists in the structure
- Data member alignment rules:
Structure (struct).
(orUnion (union)
), the first data member is placed inOffset 0
In the future, each data member storage starts from the size of the member or the size of its children (as long as the member has children, such as arrays, structures, etc.)Start with integer multiple
(For example, if int is 4 bytes, it starts with an integer multiple of 4. Min (current start position m n) m = 9 n = 4-9 10 11 12; - Structure as a member: If a structure has some structure members, then the structure members are
Starts with an address that is an integer multiple of its internal maximum element size
. (Struct a contains struct b, which contains char, int, double, etc., so b should be stored as a multiple of 8.) - Finishing touches: the total size of the structure, i.e
sizeof
Must be the result ofInteger multiple of the largest internal member
, insufficient toA filling
.
2. Case study of structure in vivo alignment
Struct1 and Struct2 have the same attribute type, but char and int are in different order. Is the sizeof the two structs obtained by sizeof the operator the same?
It’s surprising. It’s different. Why? In combination with the above principles of internal alignment of structures, it is analyzed:
1. Struct1
- Double A: First member, 8 bytes, starting from 0,
Occupied location: 0-7
; - Char b: 1 byte, starting from 8, also an integer multiple of 1,
Occupied location: 8
; - Int c: 4 bytes, starting at 9? No, let’s start at 12,
Occupied location: 12, 13, 14, 15
; - Short D: 2 bytes, starting at 16, also an integer multiple of 2,
Occupied location: 16 17
;
Combined with the 8-byte alignment principle, the final size is 24.
2. Struct2
- Double A: First member, 8 bytes, starting from 0,
Occupied location: 0-7
; - Int b: 4 bytes, starting at 8, also an integer multiple of 4,
Occupied location: 8, 9, 10, 11
; - Char C: 1 byte, starting at 12,
Occupied location: 12
; - Short D: 2 bytes, starting at 13? No, starting at 14,
Occupied location: 14 15
;
Combined with the 8-byte alignment principle, the final size is 16.
Do we need to pay attention to the order of class arguments in development, because classes are also structs. Is this also true of classes? Don’t need to! Because classes are OC’s layer of encapsulation of structures, some memory optimizations are made, such as the memory reordering we mentioned above. And structures are kind of silly ^_^!
Attach a table of C and OBJC-C memory usage:
3. Structure nesting case analysis
If we use sizeOf to obtain the sizeOf Struct3, how much should we print?
struct Struct1 {
double a;
char b;
int c;
short d;
} struct1;
struct Struct3 {
double a;
int b;
char c;
short d;
int e;
struct Struct1 str;
} struct3;
Copy the code
With the above principles in mind, let’s do it manually:
- Double A: First member, 8 bytes, starting from 0,
Occupied location: 0-7
; - Int b: 4 bytes, starting at 8,
Occupied location: 8, 9, 10, 11
; - Char C: 1 byte, starting at 12,
Occupied location: 12
; - Short D: 2 bytes, starting at 13? No, starting at 14,
Occupied location: 14 15
; - Int e: 4 bytes, starting at 16,
Occupied location: 16, 17, 18, 19
;
Struct1 STR: the largest Struct1 is a, which is 8 bytes, and the position must be an integer multiple of 8, so start at 24;
- Double a:
Occupied location: 24-31
; - Char B: 1 byte, starting at 32,
Occupied location: 32
; - Int c: 4 bytes, starting from 36,
Occupied location: 36 37 38 39
; - Short D: 2 bytes, starting at 40,
Occupied location: 40 41
;
Combined with the 8-byte alignment principle, the final size is 48.
Was it right? Check it out, exactly:
4. Why memory alignment
The CPU reads and writes data not in bytes, but in blocks. When reading the following section of special combined memory, 8-byte reads cannot be parsed, and reading in bytes will greatly affect performance and efficiency.
When reading this special combined memory area, according to the known data combination, the maximum 4 bytes in the space to read, need to read twice, and need to merge the two data to get int.
If you use memory alignment, you can read an entire int at once. Improved read efficiency!
V. Malloc analysis and exploration
Before exploring malloc analysis, let’s introduce a case:
Result analysis:
-
Sizeof: is an operator that gets the sizeof the type (int, size_t, structure, pointer variable, etc.) — >lg1 pointer type, so returns 8 bytes;
-
Class_getInstanceSize: is a function (call) need to open up additional memory space, only when the program runs, calculation is the size of the class (at least the size of the) – > properties and member variables
- The size of the memory required by the created object
- Class_getInstanceSize, source code core
(x + WORD_MASK) & ~WORD_MASK;
8 bytes aligned. - Don’t consider
The malloc function
In this case, memory alignment is generally [8] aligned #import <objc/runtime.h>
-
Malloc_size: heap space [actual] size of memory allocated to an object — >16 bytes aligned
- On Mac and iOS, the malloc function always allocates a multiple of [16]
#import <malloc/malloc.h>
1. Malloc analysis and exploration ideas
The calloc method, one of the core steps in the alloc process, allocates memory space for an object and returns a pointer to that memory address. From the previous study, we know that the instacnceSize method calculates the memory size required by the object. Is the actual memory size allocated by the system the same as the memory size required by the object?
Prepare a copy of the libmalloc source code. Run the following program:
void *p = calloc(1, 24);
NSLog(@"%lu", malloc_size(p));
Copy the code
Apply for 24, according to the 16 byte alignment principle, the actual open control should be 32 bytes! So malloc_size of p should be equal to 32.
The result is consistent with the conjecture 32, so is the underlying processing? Explore! Trace the code running toMalloc_zone_calloc method
According to the return value, the key code is judged to be 1441 lines.
So let’s go ahead and run the program,According to the total_bytes<=NANO_MAX_SIZE, the normal process is not greater than the maximum value
, so line 886 is the key code.
The point we care about is the size setting, so determine 621 rows of key flow.
I found it in this method16 byte alignment algorithm
, that is,The size of the memory space actually created by the system
. Among themNANO_REGIME_QUANTA_SIZE = 16, SHIFT_NANO_QUANTUM = 4
, sok = (24 + 16 - 15) >> 4; Then we move it 4 bits to the left, 16 bytes aligned
!
2. Summary of memory application and allocation
When alloc creates an object, the system first uses the instanceSize method to calculate how much memory space should be allocated (16 bytes aligned by default), then uses the Calloc method to calculate the 16 bytes aligned memory size, and then allocates the memory space to the object according to the result, and returns the memory address. If the instanceSize method is aligned to 16 bytes, then the actual allocated memory size is the same as the applied memory size. If it is 8 bytes aligned, it is different. ^_^