在 Obj-C 中,如何检测内存泄漏?你知道哪些方式?
- Memory Leaks
- Alloctions
- Analyse
- Debug Memory Graph
- MLeaksFinder
泄露的内存主要有以下两种:
- Laek Memory 这种是忘记 Release 操作所泄露的内存。
- Abandon Memory 这种是循环引用,无法释放掉的内存。
什么是 悬垂指针?什么是 野指针?
- 悬垂指针
指针指向的内存已经被释放了,但是指针还存在,这就是一个 悬垂指针 或者说 迷途指针 - 野指针
没有进行初始化的指针,其实都是 野指针
retain,copy,assign,weak,_Unsafe_Unretain 关键字的理解
深拷贝 和 浅拷贝 的概念,集合类深拷贝如何实现
自动引用计数应遵循的原则
Dealloc
Dealloc调用流程
- 首先调用 _objc_rootDealloc()
- 接下来调用 rootDealloc()
- 这时候会判断是否可以被释放,判断的依据主要有 5 个,判断是否有以上五种情况
- NONPointer_ISA
- weakly_reference
- has_assoc
- has_cxx_dtor
- has_sidetable_rc
- 如果有以上五中任意一种,将会调用 object_dispose()方法,做下一步的处理。
- 如果没有之前五种情况的任意一种,则可以执行释放操作,C 函数的 free()。 5.执行完毕。
object_dispose() 调用流程。
- 直接调用 objc_destructInstance()。
- 之后调用 C 函数的 free()。
objc_destructInstance() 调用流程
- 先判断 hasCxxDtor,如果有 C++ 的相关内容,要调用 object_cxxDestruct() ,销毁 C++ 相关的内容。
- 再判断hasAssocitatedObjects,如果有的话,要调用object_remove_associations(), 销毁关联对象的一系列操作。
- 然后调用 clearDeallocating()。
- 执行完毕。
clearDeallocating() 调用流程。
- 先执行 sideTable_clearDellocating()。
- 再执行 weak_clear_no_lock,在这一步骤中,会将指向该对象的弱引用指针置为 nil。
- 接下来执行 table.refcnts.eraser(),从引用计数表中擦除该对象的引用计数。
- 至此为止,Dealloc 的执行流程结束。
内存管理方案
- taggedPointer :存储小对象如 NSNumber。深入理解 Tagged Pointer
- NONPOINTER_ISA(非指针型的 isa):在 64 位架构下,isa 指针是占 64 比特位的,实际上只有 30 多位就
已经够用了,为了提高利用率,剩余的比特位存储了内存管理的相关数据内容。 - 散列表:复杂的数据结构,包括了引用计数表和弱引用表
通过 SideTables()结构来实现的,SideTables()结构下,有很多 SideTable 的数据结构。
而 sideTable 当中包含了自旋锁,引用计数表,弱引用表。 SideTables()实际上是一个哈希表,通过对象的地址来计算该对象的引用计数在哪个 sideTable 中。
@autoreleasePool 的数据结构?
简单说是双向链表,每张链表头尾相接,有 parent、child 指针 每创建一个池子,会在首部创建一个 哨兵 对象,作为标记
最外层池子的顶端会有一个 next 指针。当链表容量满了,就会在链表的顶端,并指向下一张表。
BAD_ACCESS 在什么情况下出现?
访问了已经被销毁的内存空间,就会报出这个错误。
根本原因是有 悬垂指针
没有被释放。
autoReleasePool 什么时候释放?
App 启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是
_wrapRunLoopWithAutoreleasePoolHandler()。
第一个 Observer 监视的事件是 Entry(即将进入 Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是 -2147483647,优先级最高,保证创 建释放池发生在其他所有回调之前。
第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用 _objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即 将退出 Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
线程结束 Tls_dealloc 释放
runloop进入任务,结束任务时 释放