One, structure problem alignment principle

  1. The offset of each member of the structure relative to the starting address is divisible by its own size, and if not, a byte is added after the previous member
  2. The starting address of a struct variable is divisible by the size of its widest member, or if not, a byte is appended to the preceding member
  3. The total size of the structure is divisible by the size of the widest member; if not, bytes are appended

Verify the alignment principle

struct structA {
    double a;//[0-7]
    char b;/ / [8]
    int c;// Principle 1[9-11] must be completed, so start at 12 [12,13,14,15]
    // principle 3 the maximum sizeofA member is 8 bytes (a,b,c is 8)
};
struct structB {
    char a;/ / [0]
    struct structA b;// Principle 2 [1-7] must be completed, so start 8 [8-23]
    int c;//[24-27] Principle 3, (a,b, C maximum width B is 8) [28-31] to fill sizeofB-----32
};
Copy the code

Output validation

struct structA a;
NSLog(@"sizeofA-----%zu",sizeof(a));
struct structB b;
NSLog(@"sizeofB-----%zu",sizeof(b));
Copy the code

The output log

2021-07-20 14:56:51.861184+0800 xzwblue[6728:183043] sizeofA-----16
2021-07-20 14:56:51.861613+0800 xzwblue[6728:183043] sizeofB-----32
Copy the code

A complete understanding of the three principles of alignment is all that is required for the calculation of structures

Basic data type memory

C OC 32 – A 64 – bit
bool BOOL(64位) 1 1
signed char (__signed char)int8_t, BOOL(32 bits) 1 1
unsigned char Boolean 1 1
short int16_t 2 2
unsigned short unichar 2 2
Int, int32_t NSInteger(32-bit), boolean_t(32-bit) 4 4
unsigned int Boolean_t (64 bits), NSUInteger(32 bits) 4 4
long NSInteger(64位) 4 8
unsigned long NSUInteger(64位) 4 8
long long int64_t 8 8
float CGFloat(32位) 4 4
double CGFloat(64位) 8 8

Two, open up memory

  • The new object
@interface NBPerson : NSObject
@property (nonatomic, assign) char flag;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
//@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, assign) float height;

@end
Copy the code
  • Output test
#import <objc/runtime.h>
#import <malloc/malloc.h>


NBPerson *nb = [[NBPerson alloc] init];
NSLog(@"Object type memory size --%lu",sizeof(nb));
NSLog(@"Object memory size --% LU",class_getInstanceSize([nb class]));
NSLog(@"System allocated memory size --% LU",malloc_size((__bridge const void *)(nb)));

// Output the result
2021-07-20 16:32:36.045471+0800 xzwblue[8458:248752The memory size of the object type8
2021-07-20 16:32:36.045907+0800 xzwblue[8458:248752The size of memory used by the object40
2021-07-20 16:32:36.046018+0800 xzwblue[8458:248752[Size of memory allocated by the system48
Copy the code
  1. sizeof

Is an operator, not a function. Sizeof is passed in as a type, which is used to calculate how much memory the type takes up. This is determined by the compiler at compile time and converted directly to constants like 8, 16, and 24, rather than being calculated at run time. Arguments can be arrays, Pointers, types, objects, structures, functions, and so on

Its function is to obtain the size in bytes that is guaranteed to hold the maximum object created by the implementation.

Since the sizeof memory is determined at compile time, sizeof cannot be used to return the sizeof dynamically allocated memory space.

Nb is treated as a pointer, and the pointer type memory size is 8

  1. class_getInstanceSize

Get the memory size of the instance object of the class, and return the specific number of bytes, the essence is to get the memory size of the instance object member variables

Depending on <objc/ Runtime. h>, returns the amount of memory needed to create an instance object

View the source code

size_t class_getInstanceSize(Class cls)
{
    if(! cls)return 0;
    return cls->alignedInstanceSize();
}

uint32_t unalignedInstanceSize() const {
    ASSERT(isRealized());
    return data()->ro()->instanceSize;
}

// Return the size of the ivar(member variables) of a class
uint32_t alignedInstanceSize() const {
    return word_align(unalignedInstanceSize());
}

#  define WORD_MASK 7UL   

// Calculate memory size algorithm (8 bytes aligned)
static inline uint32_t word_align(uint32_t x) {
  // (8 + 7) & ~ 7
    return (x + WORD_MASK) & ~WORD_MASK;
}

Copy the code
  1. malloc_size

This is done by the system (with 16-byte alignment).

Depending on <malloc/malloc.h>, returns the actual amount of memory allocated by the system

Segregated_size_to_fit in malloc source analysis

#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
  1. Memory optimization
  • Class_getInstanceSize is the same as the structure memory calculation and it follows the memory alignment principle
  • What’s more, there’s also optimization, which means that the memory of a structure is affected by the order of members, and the memory of an object, no matter how your properties are arranged, the system will store the data in memory in the optimal order.
  1. Their calculation

So once we know all of this we can do our own memory calculations

@interface NBPerson : NSObject

@property (nonatomic, assign) char flag; /1@property (nonatomic, copy) NSString *name; /8@property (nonatomic, copy) NSString *nickName; /8
//@property (nonatomic, assign) int age;@property (nonatomic, copy) NSString *sex; /8@property (nonatomic, assign) float height; /4Optimal sequential calculation8(isa)+3*8+ (4+1)8 = 40
class_getInstanceSize = 40
16Byte alignment malloc_size =48
Copy the code

Third, verify optimization

@property (nonatomic, assign) char flag;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
//@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *sex;
@property (nonatomic, assign) float height;


Copy the code
    NBPerson *nb = [[NBPerson alloc] init];
    nb.flag = 'a';
    nb.name = @"The big guy.";
    nb.nickName = @"That's awesome.";
    nb.sex = @"Male";
    nb.height = 180.3;
Copy the code
(lldb) x/6gx nb
0x600001940ff0: 0x000000010398cca0 0x43344ccd00000061
0x600001941000: 0x00000001039859d8 0x00000001039859f8
0x600001941010: 0x0000000103985a18 0x0000000000000000

// This is very intuitive
0x000000010398cca0 --- isa
0x0000000000000000-- Replenish memory// This is not 8 bytes of data
(lldb) po 0x43344ccd00000061
4842579942682132577

// The type is incorrect
(lldb) po 0x43344ccd
1127501005

(lldb) po/f 0x43344ccd
180.300003

(lldb) po/c 0x00000061
a\0\0\0

(lldb) po 0x00000001039859d8LLDB Po0x00000001039859f8That's LLDB Po0x0000000103985a18Copy the code

After a little bit of manipulation, it turns out that the char and float are not in the same order, but the system automatically optimizes them, and putting them together, I have to say, is really remarkable

Fourth, problem exploration

  1. Why are structures byte aligned?
The function of byte alignment is not only easy for CPU to access quickly, but also reasonable use of byte alignment can effectively save storage spaceCopy the code
  1. What is instance alignment?
Simply said is in the open up a piece of memory space, can only open up16Integer multiple bytes of memory space. So in order to16Bit for unit length to open up space, can ensure the continuity of memory on the uniformity.Copy the code
  1. Why 16-byte alignment?
We all know that a byte is a unit of memory capacity,1Memory, you could call it1Bytes. However, when the CPU reads memory, it does not read in bytes, but in "blocks", so you often hear a piece of memory, "block" size is also the memory access strength. If it is not aligned, the CPU will have to spend a lot of effort trying to figure out how many bytes to read when we are accessing memory frequently. This will make the CPU inefficient. If you want the CPU to be efficient without reducing the number of accesses, you need to find a specification, and the specification is byte alignment. Apple to take16Byte alignment, because in the object of OC, the first byte is called`isa`Pointer, it has to exist, and it takes up8Bit bytes, even if there are no other properties in your object, there must be one`isa`, the object should at least occupy8Byte. If the8With byte alignment, if two consecutive pieces of memory are objects without attributes, their memory Spaces will be completely next to each other, which can be confusing. In order to16The byte is a block, which ensures that the CPU can read in blocks, which is more efficient, but also less cluttered.Copy the code