iOS内存管理

·  阅读 216

1.内存布局

程序加载到内存最终会分为三段,我们所写的代码数据都在代码段,已初始化的静态变量,全局变量存在于已初始化数据区,未初始化的静态变量,全局变量存在于为初始化数据区。我们定义的方法,基本数据类型都在栈区。我们创建的对象和copy到堆上面的block都存在于堆区

栈区:一般都是方法的调用
堆区:对象的处理都在堆上面
bss:未初始化的全局变量和静态变量
data:已初始化的全局变量和静态变量
Text:程序代码

2.内存管理方案
1.一些小对象,比如NSNumber,采用的是TaggerPointer。
2.NONPIOINTER_ISA,在64位架构下,isa指针本身是占64个字节的,实际上有32位,或者40位就够用了,苹果为了提高内存利用率,就把剩下的比特位用来存内存管理相关的信息。
3.散列表,其中包含自旋锁,弱引用表,引用计数表。
自旋锁:自旋锁本身是一种忙等的锁。如果当前锁已被其他线程获取,当前线程就会不停的试探当前锁是否被释放。如果释放了就第一时间去获取这个锁。它适用于轻量访问
弱引用表 它是一个hash表结构,他的key是对象的指针,通过hash函数能查找到他对应的弱引用的对象存储位置。 引用计数表
它是一个hash表结构。保存着对象的引用计数 //为什么引用计数表要使用hash表来保存。是为了提高效率

//sideTables sideTables的本质是一张hash表,他的key是对象的指针,他的value是对象对应的sideTable

3.ARC & MRC
MRC:手动引用计数
alloc retain release retainCount autorelease dealloc ARC 自动引用计数
ARC是编译器和runtime协作的结果
ARC中禁止手动调用retain release retainCount dealloc
ARC中新增weak,strong等关键字

4.自动释放池
autoreleasepool
自动释放池是以栈为节点的通过双向链表组成的数据结构 他是和线程一一对应的

autoreleasePoolPage next 指向栈中下一个可填充的位置
parent指向父节点
child指向子节点
thread 线程

当我们把一个对象放入autoreleasepoolpage里面的时候,会首先找到next指针所在的位置,然后把next指针那里设置一个哨兵值,也就是nil,然后把next指针指向下一个可入栈的位置。

autoreleasePoolPage:: pop
根据传入的哨兵对象找到对应的位置
给上次push操作之后添加的对象依次发送release消息
回退指针到正确的位置

自动释放池是什么时候释放的
在当次runloop将要结束的时候调用autoreleasePoolPage::pop来释放对象

多次嵌套就是多次插入哨兵对象

autorelease
当对象调用autorelease方法后会被放到自动释放池中延迟释放时机,当缓存池需要清理dealloc的时候,会向这些autoreleased对象做release操作

autorelease操作跟push实现的操作基本一致,只不过多插入了一个具体的autoreleased对象

autoreleasepool的使用
在for循环中alloc图片数据等内存消耗较大的场景手动插入autoreleasepool

循环引用 自循环引用 当前对象有一个成员变量是obj,当前对象强持有obj,obj又指向当前对象
相互循环引用 A指向B,B又指向A
多循环引用 A指向B,B指向C,C指向A

如何破除循环引用
1.避免循环引用
2.在合适的时机手动断环

代理
代理方一般都会强引用delegate,为了防止循环引用,我们需要对委托方的代理用weak修饰

block(__weak,__block,__unsafe_unretained)
block在copy的时候会对block内部的对象进行强引用的
self将block作为自己的属性变量,对他进行强引用,而在block方法体内,block又会对self进行强引用,此时就形成了一个循环引用
在ARC中,在被拷贝的block中无论是直接引用self。还是通过self的成员变量间接引用self,都会造成循环引用 __Block一般用于block的循环引用
在MRC下,__block修饰对象不会增加其引用计数,避免了循环引用
在ARC下,__block修饰的对象会被强引用。无法避免循环引用。需要手动解环

__unsafe_unretained
修饰对象不会增加引用计数,避免了循环引用
如果被修饰的对象在某一时机被释放了,我们再去访问这个对象会产生悬垂指针,造成内存泄漏

分类:
iOS
标签:
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改