iOS内存管理方案 - Go语言中文社区

iOS内存管理方案


不同场景下的内存管理方案:
1 小对象采用TaggedPointer
2 Arm64架构下的iOS应用程序采用的是NONPOINTER_ISA(本身占64bit位,实际上32位就够用了,剩余的苹果为了提高内存的利用率,剩余位存储了内存管理相关的内容)
第一位如果是0代表isa只是存isa指针的,如果是1代表是优化过的,第2位表示当前对象是否有关联对象has_assoc,第三位has_cxx_dtor表示当前变量是否用到c++代码或者c++一些内容,第4位到第32位(也就是33位)是当前对象的类对象的指针地址, 接下来有weakly_referenced是否有相应的弱引用指针,还有deallocating标志当前对象是否再进行dealloc操作,还有当前的引用技术到达上限的话就外挂一个has_sidetable_rc散列表,接下来是extra_rc额外的引用计数如果引用计数在一个很小的范围内就会存到isa指针当中
3 散列表(引用计数表和弱引用表)SideTables
在这里插入图片描述
为什么不是一个sideTable而是多个sideTable组成一个sideTables这么一个数据结构
假如把所有对象的弱引用计数都放在一个大表中,如果我要操作某一个对象值进行修改,由于对象可能是在不同的线程当中进行分配创建的,那么需要加锁处理才能保证访问安全,存在效率的问题,如果有成千上百个对象,每个存储的对象引用计数改变的时候都锁住,就存在效率的问题,为了解决效率问题提供了分离锁的技术方案比如非嵌入式原来是64个SideTable那么现在就用8个(N = 64),对8个锁分别加锁,如果两个对象不在一个表中就可以同时进行加锁.
如何实现快速分流:(SideTables的本质是一张hash表)
在这里插入图片描述
在这里插入图片描述
Spinlock_t 是"忙等"的锁,如果当前锁已被其他线程获取, 那么当前线程就不断的判断这个锁是否有被释放,如果释放掉自己第一时间获取这个锁, 自旋锁适用于轻量访问
比如其他锁,信号量,看到当前锁已经被其他线程获取,那么当前线程就会阻塞休眠,等到其他线程释放锁后来唤醒当前线程.

RefcountMap:引用计数表是哈希表,提供查找效率避免for循环遍历
在这里插入图片描述
size_t中每个位的意思
在这里插入图片描述

weak_table_t 弱引用表

在这里插入图片描述

ARC:是LLVM和Runtime协作的共同结果
引用计数管理:dealloc实现:
在这里插入图片描述
object_dispose()实现

在这里插入图片描述
objc_destructInstance()实现
在这里插入图片描述
clearDeallocting()实现
在这里插入图片描述

弱引用管理:
在这里插入图片描述
添加weak变量
在这里插入图片描述

自动释放池:以栈为节点通过双向链表(ParentPtr, ChildPtr)的形式组合而成.是和线程一一对应的
AutoreleasePool的实现原理是怎么样的?为何可以嵌套使用
编译器会将@autoreleasepool{}改写为
void *ctx = objc_autoreleasePoolPush(); -> void * AutoreleasePoopPage::push(void)
{}中的代码
objc_autoreleasePoolPop(ctx); -> AutoreleasePoopPage::pop(void * ctx)
一次pop实际上相等于一次批量的pop操作
在这里插入图片描述
next实际上指向栈当中下一个可以填充的位置, 如果再进行一次push入栈操作就可以添加一个autorelease对象到了next这里,把当前next位置置为Nil称为哨兵对象,再将Next指针指向下一个可以入栈的位置, 实际上每次进行一个autoreleasePoolPage代码块的创建相等于不断的在栈当中插入哨兵对象. 下面的图中最下面是autoreleasepoolpage自身所占用的内存,上面是存储花括号当中所填充的autorelease对象,同样的栈是从高地址到低地址,
在这里插入图片描述
[objc autorelease]在这里插入图片描述
autoreleasePoolPage::Pop,
根据传入的哨兵对象找到对应位置 (记AutoreleasePoolPage::push函数返回值的哨兵对象),
2 给上次push操作之后添加的对象一次发送release消息,
3 回退next指针到正确的位置
在这里插入图片描述
在这里插入图片描述
在viewDidLoad中创建的对象是在什么时候释放的?
实际上在每一次runloop循环过程当中都会在他将要结束的时候将前一次创建的autoreleasePoolPage进行pop操作,再一个新的autoreleasePool
在当次runloop将要结束的时候调用autoreleasePoolPage::pop()
多层嵌套就是多次插入哨兵对象
比如每次进行一个autoreleasepool代码块的创建时,系统会进行一个哨兵对象的插入
完成新的autoreleasepoolPage的创建,如果当前page没有满就不用创建page

什么时候手动创建autoreleasePool:
在for循环中alloc图片数据等内存消耗较大的场景手动插入autoreleasePool, 降低内存峰值

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u012581760/article/details/108351244
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-30 22:13:30
  • 阅读 ( 1177 )
  • 分类:研发管理

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢