引文:
-
内存布局
-
内存管理方案
-
数据结构
-
ARC&MRC
-
引用计数
-
弱引用
-
自动释放池
-
循环引用
image.png
内存布局 (从低到高分配)
栈(stack): 方法调用
堆(heap): 通过alloc分配的对象
bss: 未初始化的全局变量等
data: 已初始化的全局变量等
text: 程序的代码段
内存管理方案
TaggedPointer: 程序对小数据量优化(防止crash等)
NONPOINTER_ISA
散列表
怎样实现快速分流?
image.png
数据结构
Spinlock_t (自旋锁)
Spinlock_t 是一种"盲等"的锁,(一直循环去询问访问)
适应于轻量的访问
RefcountMap (引用计数表)
image.png
weak_table_t (弱引用表)
使用对象指针作为key,通过hash函数找到到对应的value
image.png
ARC (自动引用计数)
ARC是
LLVM和Runtime协作的结果ARC中禁止手动调用
retain/release/retainCount/dealloc方法ARC中新增
strong和weak属性关键字
引用计数管理
alloc的实现
经过调用链最终会调用c函数
calloc方法, 并且引用计数不会+1
retain实现
SideTable &table = SideTables()[this];
size_t &refcntStorage = table.refcnts[this];
refcntStorage += SIDE_TABLE_RC_ONE;
retainCount实现
SideTable &table = SideTables()[this];
size_t refcnt_result = 1;
RefcountMap::iterator it = table.refcnts.find(this);
refcnt_result += it->second >> SIDE_TABLE_RC_SHIFT
image.png
object_dispose()实现
image.png
自动释放池
是以栈为方式的通过双向链表的形式组合而成的
是和线程一一对应的
编译器会将@autoreleasepool{} 改写为:
void *ctx = objc_autoreleasePoolPush();
// 业务逻辑
autoreleasePoolPop(ctx)
AutoreleasePoolPage
image.png
AutoreleasePoolPage::pop
根据传入的对象找到入栈的对应位置.
给上次push操作之后添加的对象依次执行release消息
回退next指针到正确的位置
在每次runloop将要结束的时候调用AutoreleasePoolPage::pop()
多层嵌套就是多次插入哨兵对象
在for循环中alloc图片数据等占用内存比较大的场景中手动调用autoreleasePool
循环引用
类型:
- 自循环引用
- 相互循环引用
- 多循环引用
一般代理/bolck/NSTimer/大环引用 都有可能引起循环引用, 所有开发者应该尽量避免循环引用,
如果已经产生了循环引用,则需要在合适的时机手动断环
解决方案:
__weak
一般采取这种方式解决循环引用(修饰对象)
OC的特点会对weak修饰的对象在释放的时候自动置为nil
__block
MRC:__block修饰的对象不会增加引用计数,避免了循环引用
ARC:__block修饰的对象会产生强引用,无法避免循环引用.需要手动解除
__unsafe_unretained
修饰的对象不会产生循环引用,但是如果对象在某一时刻被释放了会产生悬垂指针
关于NSTimer 产生的循环引用我们可以采用中间对象的形式来解决













网友评论