iOS 底层探究:内存对齐2

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战 上文咱们俩节了内存对齐的一些内容,今天来继续学习。markdown

对齐原理分析

已知系统会根据数据类型跳过部份内存,那跳过的部分为何不能存储数据?函数

25092736-d3c3d3cb444db5e0.png

如上图所示,对于不优化连续存储的状况,CPU读取8~15的内存数据,须要先读取1字节再读取4字节,CPU对于要读取的数据大小是有变化的。而优化后CPU先读取4字节(因为白色3字节空白因此能够直接读取4字节)再读取4字节再这段内存中是没有变化的。相比于第一种状况,优化后CPU要进行的操做变少了,这就实现了通过空间换取时间post

系统内存开辟

分析了内存对齐原理,下面咱们来看一下系统是如何开辟内存的。学习

1. 案例

PDObject定义以下:优化

@interface PDObject : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) long height;

@end
复制代码

调用:atom

#import "PDObject.h"
#import <objc/runtime.h>
#import <malloc/malloc.h>

PDObject *pdObj = [PDObject alloc];
pdObj.name = @"HotpotCat";
pdObj.age = 18;

NSLog(@"sizeof:%zu class_getInstanceSize:%zu malloc:%zu",sizeof(pdObj),class_getInstanceSize([PDObject class]),malloc_size((__bridge const void *)(pdObj)));
复制代码

那么sizeof、class_getInstanceSize、malloc_size分别输出多少呢? 验证:spa

sizeof:8 class_getInstanceSize:40 malloc:48
复制代码
  • pdObj是一个结构体指针sizeof返回8
  • class_getInstanceSize因为存在isa8字节对齐因此返回40 。
  • malloc_size为何返回48呢?

在系统的内存堆区中对象的内存是16字节对齐,成员变量是以8字节对齐(结构体内部)。对象与对象是16字节对齐。3d

image.png

2.为何以16字节对齐?

为何对象不以8字节对齐?而以16字节对齐?指针

image.png 假如一个对象内部成员变量都是8字节大小。code

  • 以8字节对齐,内部没有多余空间,更容易发生访问错误。
  • 以16字节对齐内部有多余空间,不容易发生访问错误。

对于64字节的空间:

16 32 48 64
8 16 24 32 40 48 56 64
复制代码

以8字节对齐须要访问8次,以16字节对齐须要访问4次

  • 明显以16字节对齐访问对象和成员变量碰到一块儿的几率小了。16字节对齐4次,8字节对齐8次。
  • 任何对象都继承自NSObject,可是不多有对象只有一个isa。因此最小的对象都应该是16。
  • 若是用32字节对齐呢?很明显空间浪费太大了。

成员变量字节对齐是8字节对齐,对象的内存对齐市16字节对齐

总结

  • 结构体对齐(三个原则)
    • 三个原则
      • 数据成员对齐规则:从成员大小或者成员的子成员大小的整数倍开始。
      • 结构体做为成员:从内部成员最大元素的整数倍地址开始存储。
      • 补齐:必须是内部最大成员的整数倍,不足的要补齐。
    • 对齐原理:优化CPU读取速度,以空间换时间。
    • 结构体嵌套补齐从内部开始补齐。
  • 内存大小获取
    • sizeof:是运算符,不是函数。获取对象的长度(对象自己)。
    • class_getInstanceSize:获取类的实例所占用的内存大小。大小只与成员变量有关。
    • malloc_size:alloc中实际开辟的空间。
  • calloc 16字节对齐,最小返回16.
    • 最终分配的内存大小逻辑在segregated_size_to_fit中。以16字节对齐向上取整
    • 为何以16字节对齐?减小访问错误。
相关文章
相关标签/搜索