一.内存布局

1.stack:方法调用
2.heap:通过alloc等分配的对象
3.bss:未初始化的全局变量和未初始化的静态变量等
4.data:已初始化的全局变量和已初始化的静态变量等
5.text:程序的代码段
二、内存管理方案
OC针对于不同场景的管理方案
1.TaggedPointer:针对小对象(NSNumber等)
2.NONPOINTER_ISA:针对64位架构下的ios应用程序,isa占64bit的,实际上32bit或者40bit就够用了,其他的为了提升利用率,用于内存管理方面的相关内容,所以说这叫非指针型的isa
3.散列表:是一个复杂的数据结构(包括了引用计数表,和弱引用表)
散列表的实现方案是通过SideTables方案来实现的,在不同的系统下SideTables的SideTable是有不同的个数的,在非嵌入式系统下有64个。入下图所示


三、MRC
1.alloc:给对想分配内存空间 (实现:1.经过一系列函数的封装和调用,最终调用了c函数的calloc。2.此时并没有设置引用计数加1)
2.retain:引用计数加1
retain实现:
SideTable& table = SideTables()[this] ;
size_t& refcntStorage = table.refcnts[this];
refcntStorage += SIDE_TABLE_RC_ONE;
通过两次Hash查找,查到当前对象引用计数表,执行加1造作
3.release:引用计数减1
release实现
SideTable& table = SideTables()[this] ;
RefcountMap::iterator it= table.refcnts.find(this);
it->sencont -= SIDE_TABLE_RC_ONE;
4.retainCount:获取当前对象的引用计数值
retainCount实现
SideTable& table = SideTables()[this] ;
size_t refcnt_result = 1;
RefcountMap::iterator it = table.refcnts.find(this);
refcnt_result += it->sencont >> SIDE_TABLE_RC_SHIFT;
5.autorelease:如果当前对象调用了autorelease操作会在autoreleasepool结束的时候会调用release操作进行引用计数减1
6.dealloc:显式调用super.dealloc来释放或者废弃父类的相关成员变量

nonpointer_isa:非指针型isa
weakly_referenced:当前对象是否有weak指针指向它
hea_assoc:当前对象是否有关联对象
has_cxx_dtor:判断当前对象内部实现是否有c++实现的内容以及当前对象是否使用ARC来管理内存
has_sidtable_rc:当前对象是否通过sidetable引用计数表来维护的
free():C函数清理内存

objc_destructInstance()实现

clearDeallocation()实现

四、ARC
1.ARC其实是编译器自动添加retain和release之外还需要runtime功能进行支持,然后由LLVM编译器和runtime协作才能组成ARC全部的功能
2.ARC中禁止手动调用retain/release/retainCount/dealloc(可以重写dealloc,但是不能显式调用super.dealloc)
3.ARC中新增了weak、和Strong属性关键字
五、弱引用管理

1.系统是怎样把一个weak变量添加到它对应的弱引用表当中的?
一个被声明__weak的对象指针,经过编译器编译之后,会调用objc_initWeak() 函数,经过一系列函数调用,会在weak_register_no_lock()函数当中进行弱引用添加,具体添加的位置是通过一个hash算法来查找的,如果查找的当前对象已经有了弱引用对象数组,就把新的弱引用对象添加到弱引用数组中,如果没有的话从新创建一个弱引用数组然后把第0个位置添加上弱引用指针
2.面试题:当一个对象被废弃后,weak变量为什么会被置为nil
当一个对象被dealloc之后,在dealloc内部实现当中会调用弱引用清除的函数weak_clear_no_lock(), 在该函数的内部实现当中根据当前对象指针查找当前对象相对应的的弱引用把当前对象的弱引用都拿出来形成一个数组,遍历弱应用数组当中所有的弱引用指针分别置为nil
六、自动释放池




AutoreleasePoolPage::push的实现原理:next指向一个空地址,在调用AutoreleasePoolPage::push的时候会在next指向的空地址添加一个哨兵对象,next指针指向下一个可入栈的位置
AutoreleasePoolPage::pop实现原理:根据传入的哨兵对象找到正确的位置,给上次push操作之后添加的对象依次是发送release消息,然后回退next指针到正确的位置。
1.AutoreleasePool的实现原理是什么?
是以栈为节点通过双向链表的形式组合而成
2.AutoreleasePool为何可以嵌套使用?
多层嵌套就是多次插入哨兵对象,每次进行@Autorelease代码块创建的时候系统就会为我们进行一个哨兵对象的插入,然后完成一个新的autorelease创建
3.什么是自动释放池或者说自动释放池的结构是怎样的?
是以栈为节点通过双向链表的形式组合而成
在for循环中alloc图片数据等内存消耗较大的场景手动插入autoreleasePool每次for循环都进行一次内存释放来降低内存的峰值,防止内存过大所导致的一些问题。
网友评论