一、iOS的是怎样进行内存管理的
关于iOS的内存管理,可以从管理模式和引用计数来进行阐述:首先我们的iOS的内存管理可以分为MRC、ARC这两种管理模式
1、他们的共同点
首先都是通过控制引用计数来进行内存管理的,当对象的引用计数为0的时候,对象会被释放;另外它们都遵守下面几个原则:1)谁生成的对象,谁持有;2)不是自己生成的对象,自己也可以持有;3)不再需要自己持有的对象,要进行释放;4)不是自己持有的对象,自己没法进行释放。
2、他们的不同点
1)在MRC模式下需要我们手动的去控制引用计数,当一个对象想要持有一个非自己创建的对象的时候,需要先向这个对象发送retain消息,当不需要再持有这个对象的时候,需要向这个对象发送release或者autorelease消息。
2)而在ARC模式下引用计数是由编译器和runloop共同管理的,编译器在编译代码时会在适当的位置自动加入retain、release、autorelease的相关代码,结合runloop的pop和push方法来进行管理。
3)另外在ARC模式下,weak指针指向的对象在被释放的时候,weak指针会被自动置为nil。
3、引用计数于原理
1)在旧版本中,可根据对象的内存地址经过哈希查找,从SideTables中找到它所对应的SideTable,然后在该SideTable表中的引用计数表RefcountMap中以对象的内存地址取负为key,取出该对象的引用计数。
2)在新版本中,首先看对象是否是TaggedPointer对象,如果是则返回对象的地址强转的unsigned long(无符号整型)。如果不是TaggedPointer对象,再看一下对象是否开启了isa指针的优化,isa指针的nonpointer字段为0代表没有开启优化,为1代表开启了优化;
如果没有开启优化,此时对象的引用计数只存在于它对应的引用计数表RefcountMap中。
如果开启了优化,对象的引用计数会存放在isa指针的extra_rc字段上,extra_rc字段最大可存储19位二进制数,当引用计数增加extra_rc字段出现上溢时,会分开存储,一半存储到引用计数表RefcountMap中,此时isa指针的has_sidetable_rc字段会由0变为1;这种情况下当引用计数减少extra_rc字段出现下溢时,会将引用计数表RefcountMap中的引用计数取出来-1,存入到extra_rc字段中,然后删除引用计数表RefcountMap中的这条记录;如果随着引用计数的减少extra_rc字段继续出现下溢,则会调用dealloc。
4、weak的基本原理
1)在说weak的基本原理之前首先要了解一下弱引用表weak_table_t存储位置和基本结构,在app启动时,runtime会创建一个SideTables表
#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
enum {
StripeCount = 8
};
#else enum {
StripeCount = 64
};
#endif
这个表中保存了多个SideTable表的内存地址,我们可以根据对象的内存地址经过哈希查找,找到其所在的SideTable表,每个SideTable表中都包含一个自悬锁、一个引用计数表RefcountMap和一个弱引用表weak_table_t,每个weak_table_t表中会含有一个weak_entries,每个weak_entries中可以含有多个weak_entry_t,每个weak_entry_t中会存有一个对象的内存地址和该对象所有的weak 指针组成的数组。
2)当初始化weak变量时,会调用objc_initWeak(id *location, id newObj)方法创建weak指针,当给weak指针赋值时会调用objc_storeWeak(id *location, id newObj)方法,更新指针的指向(如果weak指针有旧值,先清理旧值,然后再设置新值),如果此时能通过weak指针所指向对象的内存地址,找到该对象对应的weak_entry_t,就直接将此weak指针添加到这个weak_entry_t的指针数组里面;如果没有找到对应weak_entry_t就创建一个,并插入到对应的weak_table_t中,再将weak指针添加到新创建的weak_entry_t的指针数组里面。
3)当删除weak指针时,也是通过weak指针所指向对象的内存地址,找到该对象对应的weak_entry_t,从这个weak_entry_t的指针数组里面删除该weak指针,如果删除该weak指针后针数组为空数组,则将这个weak_entry_t从对应的weak_table_t中移除。
4)当weak指针指向的对象在释放时,会调用objc_clear_deallocating这个方法,在这个方法中会根据对象的内存地址找到其所对应的weak_entry_t,然后将该weak_entry_t的指针数组中所有的weak指针置为nil,最后将这个weak_entry_t移除。(weak_entry_t其实是一个联合体,里面保存有对应的key和weak指针组成的数组)
5、了解一下对象的Retain的流程
6、了解一下对象的Release的流程
7)了解一下SideTable是散列表,散列表实际上是一张哈希表,结合了两种数据结构(数组链表),既方便查找,又方便插入
二、面试问题
请介绍一下iOS中的内存管理方式,包括ARC和MRC两种方式?
请解释一下strong和weak关键字的区别和作用?
请介绍一下weak关键字的实现原理?
请解释一下isa指针的优化方式?
请解释一下循环引用的问题,以及如何避免循环引用?
请介绍一下iOS中的内存泄漏问题,以及如何避免内存泄漏?
请介绍一下autorelease池的作用和实现原理?
怎么样进行内存泄漏的排查和解决?
对于大内存的处理和优化,你有哪些思路和方法?
对于内存问题的优化,你有哪些实际的经验和技巧?
参考:http://www.uiimage.com/sidetables、https://blog.csdn.net/qq_45598937/article/details/127284883