In iOS development, we are not very familiar with the size of the memory space of an object. It is not clear how much storage space is allocated for an object. In this article, we will explore how the memory space is allocated.

The preparatory work

The amount of memory used by various data types in iOS

Method of calculating the size of memory

  • Sizeof () : gets the sizeof the data type, for example

    // a = 1 int a = sizeof(char); //long is 8 bits, so b = 8 int b = sizeof(long); Int c = 4 int c = sizeof(int);Copy the code

  • Class_getInstanceSize () : Calculates the actual memory usage of the object, as described in the examples below

  • Malloc_size () : calculates how much memory the system eventually allocates to the object, which I’ll explain with class_getInstanceSize below

Object memory space

We know from the iOS alloc exploration above that when alloc an object without any attributes, the size of memory obtained is 16 bytes (ISA occupies 8 bytes, the remaining 8 bytes for expansion use), but when the object has attributes? Let’s look at the LGPerson object as an example.

LGPerson is an attribute

The following code

@property (nonatomic, copy) NSString *name;

LGPerson *person = [LGPerson alloc];
NSLog(@"%lu",sizeof(person));
NSLog(@"%lu",class_getInstanceSize([person class]));
NSLog(@"%lu",malloc_size((__bridge const void*)person));
Copy the code

The printed result is

We find that sizeof turns out to be 8, because we’re printing the type of person’s ISA pointer, so it’s 8;

Class_getInstanceSize results in 16, because the Person object is 16 when it has no attributes, and eight bytes are free. Exactly those eight bytes are occupied by the name attribute, so 8 + 8 = 16;

Malloc_size also results in 16, because the person object actually takes up exactly 16 space, which is a multiple of 16, so 16.

So what are the results of these three calculations when we continue to add an int?

@property (nonatomic, assign) int age; / / 4Copy the code

Print the result

We were surprised to find that sizeof remains the same and class_getInstanceSize turns out to be 24. Because we added the int property, it takes 4 bytes, to satisfy memory 8-byte alignment, so 8 + 8 + 8 = 24;

Malloc_size becomes 32, and since 24 is not a multiple of 16, it is 32.

Memory distribution region

Assuming that the storage starts at 0, the LGPerson object (with name, age, and C1 attributes) is roughly distributed as shown in the figure below

Summary of object memory distribution

  • Objects are aligned with 16 bytes. The space allocated by the system must be a multiple of 16 bytes
  • The amount of space an object takes up depends on its properties, which follow an 8-byte alignment. For example, the name property starts at position 8 (NSString is 8 bytes, 8%, 8 = 0, so start at position 8, otherwise start at position 16).

Study on structure in vivo

Structure code analysis

Let’s look at the following code

struct LGStruct1 { double a; / / 8 [0, 7] char b; //1 [8] int c; / / 4 [12] short d; / / 2 [16]} struct1; //24 struct LGStruct2 { double a; / / 8 [0, 7] int b; // 4 [8,11] char c; // 1 [12] short d; //2 [14,15] struct LGStruct1 STRCT; / / 24 16 [33] 6} struct2; //40 NSLog(@"struct1 = %lu",sizeof(struct1)); NSLog(@"struct2 = %lu",sizeof(struct2));Copy the code

Struct1, struct2, struct1, struct2, struct1, struct2

Structure is summarized in vivo

According to the printed results, we found that the space occupied by each structure is exactly what we calculated. So how are structures distributed in vivo?

The size of the memory used by the struct1 is a multiple of 8, so the size of the memory used by the struct1 is 24.

Struct2 has a struct1 in its variables, and the most used variable in struct2 is still a double a, so the memory used by struct2 must also be a multiple of 8, because it contains the struct1, So it needs to add the number of bytes of struct1, which is estimated to be 40.

Summary of Memory alignment

  • Data member alignment: The first data member of a struct (or union) is placed at offset 0, and the starting position of each data member is from the size of the member or the size of 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. Min (current start position m,n)m=9n=4 M indicates the start position of the current member, and n indicates the number of bits required by the current member. If the condition m is divisible by n (that is, m % n == 0), n is stored from the position of M, otherwise continue to check whether M = m+1 is divisible by n until it is divisible, thus determining the starting position of the current member.
  • Data members are structures: When structures are nested, the length of the data member is the memory size of the largest member of the external structure. For example, if structure A nested structure B contains char, int, double, etc., the length of B is 8

  • The total sizeof the structure, the result of sizeof, must be an integer multiple of the largest member within the structure