1. Internal alignment of structures

Structure alignment rules:

1: Data member alignment rules: The data member of a struct (or union), the first data member is placed at offset 0, and the starting position of each data member is from the size of the member or the size of the member’s 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. Min (current starting position m n) m = 9 n = 4 9 10 11 12

2: Struct as members: If a structure has some struct members, then the struct members are stored from an integer multiple of the size of the largest element in the structure.

The total sizeof the structure, the result of sizeof, must be an integer multiple of its largest internal member. What is lacking must be made up.

According to the above rules, let’s do some exercises:

struct LGStruct1 {
    int a;      / / [0-3]
    char b;        / / [4]
    int c;         // 5 6 7 [8 9 10 11]
    short d;       / / [12, 13]
}struct1;
Struct1 = 16 bytes; struct1 = 16 bytes; struct1 = 16 bytes

// Struct2 memory alignment calculation
struct LGStruct2 {
    int a;      	 / / [0-3]
    int b;         / / [4-7]
    char c;        / / [8]
    short d;       / / 9 [10, 11]
}struct2;
// The internal maximum is int, i.e. 4 bits, so 4 bytes need to be aligned, struct1 is 12 bytes

// Struct3 memory alignment calculation
struct LGStruct3 {
  	
    double a; 	 / / [0]
    int e;       // [8 9 10 11]
    struct LGStruct1 str;  // The largest element is int, so it is equivalent to a 4-bit multiple to start storage, [12-28]
}struct3;
// The largest internal element is double, so 8-byte alignment is required, struct3 is 32-byte

struct LGStruct4 {
    char a;          / / [0]
    struct LGStruct3 str;  // The largest element is double, a multiple of 8 begins storage, [8-39]
}struct4;
// The largest internal element is LGStruct3, which has a maximum internal size of 8 bits, and struct4 is 40 bytes
Copy the code

Struct1 and struct2 store the same amount of content, but not the same size. Object storage is a structure that can be stored as follows:

struct Persion_2415_IMPL {                 // The data stored in Persion is a struct Persion_2415_IMPL
	struct NSObject_IMPL NSObject_IVARS;
	int _age_2415;
	NSString *_name_2415;
};
Copy the code

As you can guess from the structure stored above, the size of the storage is probably independent of member methods and class methods. After testing, it turns out there is no relationship.

Then consider whether the memory used by the object of our OC is related to the order of variables, and perform the following test

#import <Foundation/Foundation.h> #import <objc/runtime.h> #import <malloc/malloc.h> @interface Person : NSObject @end @implementation Person { //isa double a; //[8-15] char b; //[16] double c; //[24 - 31] char d; //[32] double e; // [40 - 47] char f; //[48] double g; // [56 - 63] char h; // [64] } @end @interface Student : NSObject @end @implementation Student { //isa double a; //[8-15] double b; //[16-23] double c; //[24-31] double d; //[32-40] char e; // [41] char f; // [42] char g; // [43] char h; // [44] } @end int main(int argc, const char * argv[]) { @autoreleasepool { Person * per = [[Person alloc] init]; Student * stu = [[Student alloc] init]; NSLog(@"class_getInstanceSize -- %ld %ld",class_getInstanceSize([Person class]), class_getInstanceSize([Student class])); NSLog(@"malloc_size -- %ld %ld",malloc_size((__bridge void*)(per)), malloc_size((__bridge void*)(stu))); } return 0; } /* Output: 2021-06-17 16:47:19.435118+0800 004- ISA analysis [8791:160576] class_getInstanceSize -- 72 48 2021-06-17 16:47:19.435456+0800 004-ISA analysis [8791:160576] malloc_size -- 80 48 */Copy the code

Based on the above results, it turns out that there really is a difference in memory usage, so we can optimize memory in this way. Again, if it is an attribute, will apple help us to do some optimization, found that if you change the above member variable to an attribute

/* Output result: 2021-06-17 16:29:54.056023+0800 004-ISA analysis [8613:153735] class_getInstanceSize -- 48 48 2021-06-17 16:29:54.056347+0800 [8613:153735] malloc_size -- 48 48 */Copy the code

As you can see, Apple has made memory optimization for using attributes, so if we want to declare member variables, it is usually better to use attributes to save memory.

2. Why memory alignment

Since the CPU reads a lot of double byte, 4 byte, if not memory alignment, such as structure

struct s1{
		char a;
		int b;
}
/* Memory is not aligned: Char a is stored in 0 bytes and int B is stored in 1 to 4 bytes. If it is read in 4 bytes, it is read twice, extract twice, combine 0-3, 4- 7, and then extract 1-3 from 0-3 and 4 from 4-8. If the memory is aligned: Char a is stored in 0 bytes and int B is stored in 4-7 bytes. If a 4-7 byte is read, it needs to be read once. 4-7 is read successfully
Copy the code

3. Re-explore the memory in OC

We have a question from the print that the class_getInstanceSize and malloc_size of Person are not the same size, where

  • Class_getInstanceSize: The minimum size of the object

  • Malloc_size: the actual size of the object

The value of class_getInstanceSize, for which we can easily see the reason from the structure alignment. But why is malloc_size different? We began to explore apple’s source code flow for ALLOc in OC. Then add specific exploration process and code reading source code techniques

When alloc is discovered, 16-byte alignment is performed on class_getInstanceSize. So malloc_size is going to be different.

Conclusion:

  1. We can use attributes as much as possible when declaring member variables, and Apple will help us optimize memory. Makes the memory space more economical
  2. The size of the object’s member variables (including ISA) should add up to integer multiples of 16 to reduce some waste
  3. The size of an object’s memory usage has nothing to do with object methods or class methods