内存布局
内存布局.png栈区向下扩展 堆区向上扩展 由于内存有限,如果碰面就会出现堆栈溢出的情况
在栈区里面因为方法 函数 会形成栈帧
.bss 又称静态区
.data又称全局区
如何找到对象的数值?
1.先找到在栈区的对象所对应的指针
2.根据指针找到指针所指向的那个在堆区的对象
3.在获取对象的具体数值
内存优化的原因
栈是512kb = 512*1024 字节,由于每个指针所占内存为8个字节,那么栈区大概可以存放512*1024 / 8 = 65536个指针,也就是说
超过这个数值 会出现内存溢出的情况 因此需要内存优化
全局静态变量要放在.m中,避免不必要的问题
在方法中尽量使用嵌套(封装方法 函数)来加快读取效率 因为如果变量过多,会导致函数指针更加难别识别 这个方法是空间换时间
方法和函数的区别
函数 属于整个文件 可以直接调用 把函数写在类的声明中不会被识别
//外部函数
extern void sayHi(){
printf("sayHi\n");
}
//内部函数
static void sayHello(){
printf("sayHello");
}
方法 依赖于类 不能脱离类而存在 只能通过实例对象或者类调用
@interface Person : NSObject
@property (nonatomic,copy) NSString *firstName;
//方法声明
- (void)run;
+ (void)play;
@end
@implementation Person
//方法声明实现
- (void)run{
NSLog(@"%s",__func__);
}
+ (void)play{
NSLog(@"%s",__func__);
}
@end
内存管理方案
- taggedPointer
@taggedPointer用于NSNumber NSDate NSString等内容较少的情况 节省内存空间,同时他的读取速度较快是原先的3倍 创建速度是106倍
@小对象的地址存储的内容包括有本身所代表的值和类型
taggedPointer编码.png
taggedPointer解码.png
普通的值进行编码之后 方便系统识别是否为taggedPointer 如果是taggedPointer 直接返回值 不需要漫长的寻找过程 解码是还原出taggedPointer存储的真正的地址
得出结论一个值异或2次相同的值之后得到的还是原先的值
image.png
原先是直接异或0 现在是另外的值 是加密 不希望暴露出来
image.png
第一个不崩溃 taggedPointer不经过retain release 直接返回
第二个崩溃 是多线程不断的retain release造成崩溃 不是小对象
image.png
image.png
- NONPOINTER_ISA 非指针型isa
联合体 位域优化了isa 每一位都代表不同的值
不同的架构下面 isa是不同的 能够存储更多的空间
nonpointer:表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不不⽌止是类对象地址,isa 中包含了了类信息、对象的引⽤用计
has_assoc:关联对象标志位,0没有,1存在
has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更更快的释放对象
shiftcls: 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位⽤用来存储类指针。
magic:⽤用于调试器器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced:志对象是否被指向或者曾经指向⼀一个 ARC 的弱变量量,
没有弱引⽤用的对象可以更更快释放。
deallocating:标志对象是否正在释放内存
has_sidetable_rc:当对象引⽤用技术⼤大于 10 时,则需要借⽤用该变量量存储进位
如果自定义实现了retain release allocWithZone 不再调用系统的 而是使用自己的实现的话, 那么isa是不会被优化的
- 散列表 SideTable
SideTable 包括自旋锁 引用计数表 弱引用表
为什么是多张SideTable 不是一张SideTable
1.如果一个SideTable里面有多个对象 对每个对象进行操作 会造成对SideTable的操作过于频繁 影响性能
2.由于SideTable里面有自旋锁 如果一个SideTable里面有多个对象 对每个对象进行操作时 都要进行加锁解锁 同时由于自旋锁的
特性,会造成一直处于忙等状态 违背了自旋锁的操作过于简单的设计原则
3.分成多个SideTable 会达到分离锁的效果
关于每个对象存放于哪个SideTable 是根据对象 创建的时间以及一些特殊函数等其他来进行划分的
哈希表
哈希表是结合了数组+链表
数组是查询非常快 通过下标来查询 增删复杂
链表是在数据结构中增删比较有优势
哈希表是通过下标获取具体的key value
通过拉链法解决离散冲突
SideTables里面有很多SideTable
stripeMap通过array[indexofPOINTER].value获取
网友评论