Said in the previous

The code we usually write objective-C, the underlying implementation is actually C/C++ code implementation, the high-level language through the compiler compiler, and finally translated into machine language.So, all of our objective-C object-oriented implementation is actually based on C/C++ data structures. So what data structures are objective-C objects and classes based on in C/C++?

1. The nature of the object

What kind of data structure is that? Is it an array? We all know that arrays can only store data of the same type, while objects can have different properties. For example, the Student class, which has a name (string), a height (double), and so on, are of different data types, obviously not the structure type of an array! So obviously there’s only one structure that works, and that’s struct. Is it or isn’t it? Let’s explore that.

Let’s build a project and compile it into C++

Before compiling

int main(int argc, const char * argv[]) {
	@autoreleasepool {
		NSObject *obj = [[NSObject alloc]init];
	}
	return 0;
}
Copy the code

Enter the following command to compile

clang -rewrite-objc main.m -o main.cpp

We see an outputC++The filemain.cpp When you open the compiled file, you can see,mainThe function looks like this

int main(int argc, const char * argv[]) {
 /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
  NSObject *obj = ((NSObject* (*) (id, SEL))(void *)objc_msgSend)((id) ((NSObject* (*) (id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
 }
 return 0;
}
Copy the code

For example, Windows, macOS, and iOS, we want to support C++ code on iOS, so use this command

Xcrun – SDK iphoneos clang -arch arm64 -rewrite-objc source file -o output file

Xcode builds on the arm64 architecture of the iPhone platform. -o stands for output

Run the following command

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp

The compiled underlying source code is tens of thousands of lines inLine 7400As we can see,NSObjectThe bottom isThe structure of the body

struct NSObject_IMPL {
	Class isa;
};
Copy the code

So that’s the proofOCAt the bottom is the structure, so thisClass isaWhat is it? Let’s go inside and have a look

typedef struct objc_class *Class;
Copy the code

The *Class is a pointer to the structure. How many bytes is a pointer to the structure? If it’s 64-bit, it’s 8 bytes, and if it’s 32-bit, it’s 4 bytes, so now the system is 64-bit, and in this structure, the Class ISA member variable is 8 bytes. The structure is 8 bytes long, because there are no other attributes or variables in the structure. The Class ISA member variables are included by default, so the structure is 8 bytes long.

2. The structure of the body

This code instantiates an object obj. The underlying implementation isa structure described above 👆 that contains a Class isa member variable

NSObject *obj = [[NSObject alloc]init];
Copy the code

If the isa address is 0x12300001, what is the address of the obj pointer? Alloc has allocated memory, so this pointer is the first address, and there is only one member variable in it, so the address of isa is the address of the structure in memory, so obj=0x12300001. The size of the structure is the size of the pointer, so what is the size of an NSObject in memory? Is that also 8 bytes?? It’s not. It’s 16 bytes. Ah??? Why 16 bytes?? With a confused face 🤔, then we go on to explore 👇

3. Memory alignment

We can print out and see how much memory the member variables of our instance NSObject are using. We can use the header #import

#import<objc/runtime.h>
NSLog(@"InstanceSize:%zd",class_getInstanceSize([NSObject class]));
Copy the code

And we can see that the output is8So let’s see,objThe size of the memory pointed to in the import header file#import<malloc/malloc.h>

NSLog(@"malloc_size:%zd",malloc_size((__bridge const void *)(obj)));
Copy the code

The print result is as followsAccording to the print, yes16, which also verifies the above 👆 said:NSObjectThe size of the object in memory is16Bytes.poA printYou can also view the distribution of addresses in memory

Debug->Debug Workflow->View Memory

Here is the memory allocationIt’s clear from the figure above that it is16 bytesBefore,8Who is theisaAfter,8Bits are reserved for memory allocation8Bytes. So why reserve it? Ming Ming8One is enough. Distribute16What??Memory resourcesIt is very precious!CPUIs it silly?? With that in mind, let’s move on to 👇

How much does the following code print??

@interface Student : NSObject
{
	int _age;
	int _num;
}
@end

@implementation Student

@end
Student *stu = [[Student alloc]init];
NSLog(@"InstanceSize:%zd",class_getInstanceSize([Student class]));
NSLog(@"malloc_size:%zd",malloc_size((__bridge const void *)(stu)));
NSLog(@"sizeof:%lu".sizeof(stu));
Copy the code

Print the resultThrough the commandxcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpptoThe CPP fileIs the following structure

struct Student_IMPL {
	Class isa;
	int _age;
	int _num;
};
Copy the code

becauseStudentIs inherited fromNSObjecT,StudentThere is aMember variable isaIs pointing to the superclassNSObject.isais8Bytes,intType is4One byte, total16Bytes. Then IStudentIs there one member variable missing? The result is12or16What about ????As a result,16, according to??? Why is that? This is theByte alignment.class_getInstanceSizeIs to calculate the size of a member variable of the class. In fact, it is not strictly the size of the object’s memory that is calculated, because memory is performed8Byte alignment fromobjcThe underlying source code can be seen that the core algorithm isDefine WORD_MASK 7UL ((x + WORD_MASK) & ~WORD_MASK.

Supplement:sizeofNot a function, yesC/C++An operator in thesizeof() Is an operator that determines the data type or the length of an expression.

The memory alignment of the object is actually 16 bytes aligned, so let’s explore 👇

4. Memory alignment

  1. Data member alignment rules: Structure (struct) Or in combination with (union)) data members, no

A data member is placed at offset 0, and then each data member is stored starting at 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, the data member is stored starting at an integer multiple of 4.) Min (current start position m size n) for example: m = 9 n = 4 –> 9 10 11 12 2. Struct b as a member: If a struct has a member, the member is stored at an integer multiple of the maximum size of its internal element (struct a contains struct b, and b contains char,int,double, etc., then b should be stored at an integer multiple of 8). 3. Finishing touches: the total sizeof a structure, the result of sizeof, must be an integer multiple of its largest internal member.

5. Internal alignment of structures

Osmanthus on the code, first on a few structures to taste, haha 😁

struct Student1{
	double a;       / / 8 7 [0]
	char b;         / / 1 [8]
	int c;          // 4 (9 10 11 [12 13 14 15])
	short d;        // 2 [16 17] 24
} Student1;

struct Student2{
	double a;       / / 8 7 [0]
	int b;          // 4 [8 9 10 11]
	char c;         / / 1 [12]
	short d;        // 2 (13 [14 15] 16
} Student2;

NSLog(@"Student1: %lu-Student2: %lu".sizeof(Student1),sizeof(Student2));

Copy the code

Below begin to savor these two appetizers! Simple calculation and analysis are carried out according to memory alignment principle

Student1 Memory size Detail procedure min(m, n). M indicates the current start position and n indicates the memory size.

  1. aAccounts for:8Bytes, offert starts at 0,Min (0, 8), i.e.,0 ~ 7 storea
  2. bAccounts for:1Bytes, offert starts at 8,Min (8, 1), i.e.,8 ~ 8storeb
  3. cAccounts for:4Bytes, offert starts at 12,Min (12, 4), i.e.,12 ~ 15storec9, 10, and 11 are not multiples of 4, so they should be left blank.
  4. dAccounts for:2Bytes, offert starts at 14,Min (16, 2), i.e.,16 ~ 17stored

The memory distribution of Student1 is displayed at 👇 for easy understanding

According to alignment principle 3, the total size of a structure must be its internal maximum

It is an integer multiple of the member. The insufficient member must be made up. The maximum value of Student1 is 8, so the last value is 24.

Student2 Memory size analysis

  1. aAccounts for:8Bytes, offert starts at 0,Min (0, 8), i.e.,0 ~ 7 storea
  2. bAccounts for:4Bytes, offert starts at 8,Min (8, 4), i.e.,8 ~ 11storeb
  3. cAccounts for:1Bytes, offert starts at 12,Min (12, 1), i.e.,12 ~ 12storec
  4. dAccounts for:2Bytes, offert starts at 14,Min (14, 2), i.e.,14 ~ 15stored

The memory distribution of Student2 is displayed at 👇 for easy understanding

Why doesn’t d start at 13? Because 13 is not an integer multiple of 2, so we start at 14 and end at 16 according to the alignment principle.

We’re done with our appetizers, so we’ll have another hard dish, 7788. Osmanthus serving !!!!!

struct Student3 {
	 double a; / / 8 7 [0]
	 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 Student1 str;//(20 21 22 23 [24 ~ 47])
}Student3;

NSLog(@"Student1: %lu-Student2: %lu-Student3: %lu".sizeof(Student1),sizeof(Student2),sizeof(Student3));

Copy the code

The print result is as follows

Student3 Memory size analysis

  1. aAccounts for:8Bytes, offert starts at 0,Min (0, 8), i.e.,0 ~ 7 storea
  2. bAccounts for:4Bytes, offert starts at 8,Min (8, 4), i.e.,8 ~ 11storeb
  3. cAccounts for:1Bytes, offert starts at 12,Min (12, 1), i.e.,12 ~ 12storec
  4. dAccounts for:2Bytes, offert starts at 14,Min (14, 2), i.e.,14 ~ 15stored
  5. eAccounts for:4Bytes, offert starts at 16,Min (16, 4), i.e.,16 ~ 19storee

This Student3 dish is really a bit hard! Got to chew it up. Student3 (struct Student1 STR) Student3 (struct Student1 STR) Student3 (struct Student1 STR) Student3 (struct Student1 STR) Student3 (struct Student1 STR) Student3 Struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 struct Student1 Therefore, offert must be a multiple of 8, that is, 24 bytes of memory space starting from 24 to store the struct Student1 STR.

For the sake of understanding, the following picture 👇 is drawn

6. Summary

  1. Objects are structures in nature and can be used with commandsXcrun - SDK iphoneos clang -arch arm64 -rewrite-objc source file -o output fileLooking at the underlying structure, the memory alignment of objects is16-byte alignment
  2. To obtain the size of a class member variable, use:class_getInstanceSize To view
  3. To get the actual memory size created by an object, use:malloc_sizeTo view
  4. Structure (struct) Or in combination with (union), the first data member is placed inoffsetWhere 0, the starting position for each subsequent data member is an integer multiple of the size of that member or the size of its children (as long as that member has children, such as arrays, structures, etc.) (e.gintforByte, start at an integer multiple of 4

Store. 6. If a structure has some struct members, the struct members are stored starting at an integer multiple of the maximum internal element size, which is 8 bytes aligned because the pointer size is 8. The total size of the structure must be an integer multiple of the largest member in the structure.

🌹 please bookmark + follow, comment + forward, in case you can’t find me next time, ha ha 😁🌹

🌹 welcome everyone to leave a message to exchange, criticize and correct, learn from each other 😁, improve self 🌹