Summary of basic principles of iOS
Before we explore the principles of memory alignment, let’s look at three ways to get memory size in iOS
Three ways to get memory size
There are three ways to get memory size:
- sizeof
- class_getInstanceSize
- malloc_size
sizeof
- 1.
sizeof
Is aThe operator
It’s not a function - 2. We use sizeof to calculate the sizeof memory.
The incoming
The main object of theThe data type
This is in the compilerCompilation phase
The size is determined at compile time rather than at run time. - 3,
sizeof
The resultingThe results of
Is the size of the space occupied by the data type
class_getInstanceSize
This method was analyzed in the source code alloc & init & new analysis. It is an API provided by the Runtime to get the memory size of the instance object and return the specified number of bytes
malloc_size
This function is to get the actual amount of memory allocated by the system
We can verify our results above with the output of the code below
conclusion
-
Sizeof: calculates the sizeof memory used by a type, including basic data types, objects, and Pointers
- For those similar to
int
suchThe basic data
In terms ofsizeof
What you get isMemory size occupied by data types
, different data types occupy different amounts of memory - And for things like NSObject definition
Instance objects
In terms of itsObject type
The essence ofPointer to a structure (struct objc_object)
, sosizeof(objc)
Print isThe size of the pointer to objc
We knowA pointer has a memory size of 8
, soSizeof (objc) prints 8
. Note: the 8 bytes here andisa
Pointers don’t matter at all!!) . - for
Pointer to the
So sizeof prints 8, because a pointer has a memory sizeof 8,
- For those similar to
-
Class_getInstanceSize: Calculates the actual memory usage of the object. This depends on the class attributes. If a custom class has no custom attributes and just inherits from NSObject, the actual memory usage of the instance object of the class is 8, which can be interpreted as 8-byte alignment.
-
Malloc_size: Calculates the size of the actual memory allocated by the object. This is done by the system. As you can see from the above print, the actual memory allocated is not equal to the actual memory occupied.
Internal alignment of the structure
Next, we first define two structures and calculate their memory size to introduce today’s topic: the principle of memory alignment.
The output is as follows
The only difference is that the order in which the variables are defined is not the same. So why do they take up the same amount of memory? This is the memory byte alignment phenomenon in iOS
Memory alignment rule
Each compiler on a particular platform has its own default “alignment coefficient” (also known as the alignment modulus). Programmers can change this by precompiling the command #pragma pack(n), n=1,2,4,8,16, where n is the “alignment factor” you want to specify. In ios, Xcode defaults to #pragma Pack (8), which is 8-byte alignment
There are three main principles for memory alignment, as explained in alloc & init & New. The memory alignment principle can be understood as follows:
-
[Principle 1] The alignment rule of data members can be understood as a formula of min(m, n), where M represents the starting position of the current member and N represents 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, and if m+1 is divisible until it is, the starting position of the current member is determined.
-
[Principle 2] Data member is structure: When a structure is nested, the length of the structure as a data member is the memory size of the maximum member of the external structure. For example, structure A nested structure B, char, int, double, etc., then b’s length is 8
-
The memory size of the final structure must be an integer multiple of the size of the maximum member memory in the structure.
Validate alignment rules
The following table shows the memory size occupied by various data types in ios. The memory size of the structure is calculated according to the corresponding type.
We can use the following figure to illustrate why two structures LGStruct1 and LGStruct2 memory size print inconsistent, as shown in the figure
Structure LGStruct1
Structure LGStruct2
Structure LGStruct1 memory size calculation
Calculate the memory size of LGStruct1 according to the memory alignment rule, the detailed process is as follows:
Variable a
Accounts for:8
Bytes, starting at 0, at this pointMin (0,7)
, starting from 0, i.e0 to 7 stores a
Variable b
Accounts for:1
Bytes, starting at 8, at this pointMin (8,1)
, i.e.,8 store b
Variable c
Accounts for:4
Bytes, starting at 9, at this pointMin (9,4)
9 doesn’t go into 4, and we keep moving back untilMin (12,4)
, starting from 12, i.e12 to 15 storage c
The variable d
Accounts for:2
Bytes, starting at 16, at this pointmin(16, 2)
, i.e.,16 and 17 storage d
So LGStruct1 needs 15 bytes of memory, and the maximum number of bytes of a variable in LGStruct1 is 8, so the actual memory size of LGStruct1 must be an integer multiple of 8, rounded up to 24, mainly because 24 is a multiple of 8. So sizeof(LGStruct1) is 24.
Structure LGStruct2 memory size calculation
Calculate the memory size of LGStruct2 according to the memory alignment rule, the detailed process is as follows:
Variable a
Accounts for:8
Bytes, starting at 0, at this pointMin (0,7)
, starting from 0, i.e0 to 7 stores a
.Variable b
Accounts for:4
Bytes, starting at 9, at this pointMin (8,4)
, starting from 8, i.e8-11 b storage
.Variable c
Accounts for:1
Bytes, starting at 8, at this pointMin (12,1)
, i.e.,12 c storage
The variable d
Accounts for:2
Bytes, starting at 13, at this pointMin (13,2)
13 doesn’t go into 2, so we keep moving back untilMin (14,2)
, starting at 14, i.e14 to 15 store d
So LGStruct2 needs 15 bytes of memory, and the maximum number of bytes of a variable in LGStruct2 is 8, so the actual memory size of LGStruct2 must be an integer multiple of 8, rounded up to 16, mainly because 16 is an integer multiple of 8, So sizeof LGStruct2 is 16
Structure nested structure
The above two structures are just a simple definition of the data members, the following is a more complex, the structure of the nested structure of the memory size calculation
- We first define a structure, LGStruct3, in which we nest LGStruct1, as shown below
The printed result is shown below
LGStruct3 memory calculation according to memory alignment rules, step by step to analyze the calculation process of LGStruct3 memory size
Variable a
Accounts for:8
Bytes, starting at 0, at this pointMin (0,8)
, i.e.,0 to 7 stores a
Variable b
Accounts for:4
Bytes, starting at 8, at this pointMin (8,4)
, i.e.,8-11 b storage
Variable c
Accounts for:1
D12 starts at this pointmin(12, 1)
, i.e.,12 c storage
The variable d
Accounts for:2
Bytes, starting at 13, at this pointMin (13,2)
13 is not divisible by 214 to 15 store d
The variable e
Accounts for:4
Bytes, starting at 16, at this pointMin (16,4)
, i.e.,16-19 storage e
Structure member STR
STR is a structure, according toMemory alignment Rule 2
.Structure members are stored from an integer multiple of the size of their largest internal member
And theLGStruct1
In theLargest member
Size of the8
, so STR must start at an integer multiple of 8, currently from20
Okay, so it doesn’t fit, so I need to move back to 24,24 is a multiple of 8, so it’s memory aligned, so24-47 storage STR
Therefore, LGStruct3 requires 47 bytes of memory, and the maximum variable in LGStruct3 is STR, and the maximum memory size of its member is 8. According to the principle of memory alignment, the actual memory size of LGStruct3 must be an integer multiple of 8, rounded 48, which is exactly an integer multiple of 8. So sizeof LGStruct3 is 48
Memory optimization (attribute rearrangement)
LGStruct1 adds 9 bytes through the memory byte alignment principle, while LGStruct2 only needs to complete one byte to meet the byte alignment rule through the memory byte alignment principle. Here we draw a conclusion that the memory size of the structure is related to the order of the memory size of the structure members
- If it is
A data member in a structure
Is based onMemory goes from small to large
To calculate the internal memory size of the structure according to the memory alignment rule, a larger memory padding is needed to meet the memory alignment rule.More waste of memory
- If it is
A data member in a structure
Is based onMemory from large to small
To calculate the size of the structure based on memory alignment rules, we just need toFill in a little memory padding
Can satisfy the stacking alignment rule, this way isUsed in Apple
Using space for time,The attributes of the class are rearranged to optimize memory
Take the following example to illustrate property rearrangement, or memory optimization, in Apple
- Define a custom LGPerson class with a few attributes,
- Create an instance of LGPerson in main and assign values to several of its properties
- Breakpoint debug person, based on
LGPerson
theAddress of the object
Find the value of the property - Find out by address
name & nickName
* * * * * * * * * * * * * * * * * * * * * * * * * By 4+1+1, in 8-byte alignment, not complete in the same block of memory,
Below is the memory distribution for LGPerson
2. Address 0x0000000000000000 indicates that there are unassigned attributes in person
conclusion
So, here’s a summary of apple’s memory alignment ideas:
- Most of the memory is read from a fixed block of memory
- Even though we have memory alignment in memory, but
Not all memory can be wasted
, Apple will automatically rearrange the properties so thatOptimization of memory
How much byte alignment is used?
So far, we have mentioned both 8-byte alignment and 16-byte alignment, so which byte alignment are we using?
We can analyze this by looking at the source code for class_getInstanceSize in objC4
/** * Returns the size of instances of a class. * * @param cls A class object. * * @return The size in bytes of instances of the class \e cls, Or \c 0 if \e CLS is \c Nil. */ OBJC_EXPORT size_t class_getInstanceSize(Class _Nullable CLS) OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0); ⬇️ size_t class_getInstanceSize(Class CLS) {if (! cls) return 0; return cls->alignedInstanceSize(); } ⬇️ // Class's ivar size rounded up to a poor-size boundary. Uint32_t alignedInstanceSize() const {return word_align(unalignedInstanceSize()); } ⬇️ static uint32_t word_align(uint32_t x) {//x+7 & (~7) --> 8 bytes align return (x + WORD_MASK) & ~WORD_MASK; } // where WORD_MASK is # define WORD_MASK 7ULCopy the code
Through the source code:
- For a
object
theReal alignment
是8 byte alignment
8-byte alignment is sufficient for the object - Apple’s system uses 16-byte aligned memory to prevent everything from being fault-tolerant, mainly because 8-byte alignment makes the memory of two objects close to each other more compact, while 16-byte alignment is looser, making it easier for Apple to expand.
Summarize the methods of obtaining memory size mentioned above
class_getInstanceSize
: is to use8 byte alignment
, the memory size of the attribute of the referenced objectmalloc_size
: in this paper,16-byte alignment
The actual size of memory allocated by the object must be an integer multiple of 16
Memory alignment algorithm
There are two known 16-byte memory alignment algorithms
alloc
Source code analysisalign16
:malloc
Source code analysissegregated_size_to_fit
Align16:16-byte alignment algorithm
The idea of this algorithm is already mentioned in alloc & init & New
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
Copy the code
Segregated_size_to_fit: 16-byte alignment algorithm
#define SHIFT_NANO_QUANTUM 4 #define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16 static MALLOC_INLINE size_t segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey) { size_t k, slot_bytes; if (0 == size) { size = NANO_REGIME_QUANTA_SIZE; // Historical behavior } k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta slot_bytes = k << SHIFT_NANO_QUANTUM; // multiply by power of two quanta size *pKey = k - 1; // Zero-based! return slot_bytes; }Copy the code
Algorithm principle: K + 15 >> 4 << 4, where 4 + 4 to the right + 4 to the left is equivalent to erasing the last 4 bits, the same as K /16 * 16, is a 16-byte alignment algorithm, less than 16 becomes 0
Take k = 2 for example, as shown in the following figure