OC内存管理

作者: huoshe2019 | 来源:发表于2019-10-15 15:26 被阅读0次
内存管理

一、内存布局

内存布局 内存1 内存2

二、内存管理方案

2.1、方案介绍

  • TaggedPointer
    比如NSNumber类型
  • NONPOINTER_ISA
    针对64位架构
  • 散列表
    包括引用计数表和弱引用计数表

2.2、散列表

散列表

问题1:为什么不是一个SideTable?

存在效率问题。操作其中一个对象引用计数时,会被加锁,后面对象就会要一直等待。

为了解决上述问题:引入了分离锁的计数解决方案,提高访问效率。

分离锁

问题2:怎样通过一个对象指针快速定位属于哪个Side Tables?

通过哈希查找、不涉及遍历、查找效率高。
Side Tables的本质是一张Hash表

三、数据结构

3.1、Spinlock_t(自旋锁)

  • Spinlock_t是“忙等”的锁。
  • 适用于轻量访问。

3.2、引用计数表

  • 是一个哈希表。
  • 通过哈希查找。
  • 通过指针查找引用计数。
引用计数查找1 引用计数查找2

3.3、弱引用计数表

弱引用计数表

四、MRC和ARC相关

4.1、MRC(手动引用计数)

MRC

其中红色部分不能在MRC下使用!

4.2、ARC(自动引用计数)

ARC

五、引用计数管理

  • alloc
  • retain
  • release
  • retainCount
  • dealloc

5.1、alloc实现

经过一系列调用,最终调用了C函数calloc。
此时并没有设置引用计数为1

5.2、retain实现

retain

5.3、release实现

release

5.4、retainCount实现

retainCount

这里解答了alloc为什么引用计数没有加1,而retainCount获取的数值却为1。

5.5、dealloc实现(重点)

5.5.1、 dealloc实现流程图

dealloc

5.5.2、 object_dispose实现

object_dispose

5.5.3、 objc_destructInstance实现

objc_destructInstance

问题3:通过关联对象为一个类添加实例变量,在对象的dealloc方法中是否有必要对关联对象进行移除?

没必要,因为系统已经进行移除了(如上图)。

5.5.4、 clearDeallocating实现

clearDeallocating

问题4:为什么一个弱引用对象指针,在对象销毁后,会自动置为nil?

1、因为在对象销毁后,会调用dealloc方法。
2、在dealloc内部方法实现中,会调用weak_clear_no_lock()函数。
3、在该函数内部,会根据当前对象指针,利用哈希算法,查找弱引用表,然后取出弱引用数组,遍历这个数组,将弱引用指针全部置为nil。

六、弱引用管理

问题5:一个weak变量是怎样被添加到弱引用计数表中的?

解释:
这里讲解一下weak修饰的变量会经历哪些步骤就可以了。
1、一个被声明为weak的变量,经过编译器编译后,会调用objc_initWeak()storeWeak()weak_register_no_lock()函数。
2、在weak_register_no_lock()函数中,进行一个弱引用添加。具体添加的位置,是通过哈希算法查找的。

6.1、系统内部函数调用

weak编译 objc_initWeak

weak_register_no_lock()
通过哈希算法,查找对应位置;将弱引用weak变量添加到弱引用计数表中。

6.2、清除变量,弱引用指针指向nil

dealloc内部调用

这里主要是weak_clear_no_lock起到主要作用。

七、自动释放池

问题6:下面的array什么时候释放

自动释放池

在当次runloop将要结束的时候,对前一次的AutoreleasePool进行pop操作,同时会push一个新的AutoreleasePool。

所以,当前的array会在当前runloop将要结束的时候,调用AutoreleasePoolPage::pop,对对象进行释放。

问题7:AutoreleasePool的实现原理是怎样的?

是以为节点通过双向链表 的形式组合而成。

问题8:AutoreleasePool为何可以嵌套使用?

因为多次嵌套在底层的反应是:多次插入哨兵对象。如果当前AutoreleasePoolPage没有满,当然可以插入对象。

问题9:什么是自动释放池?

是以为节点通过双向链表 的形式组合而成。

问题10:AutoreleasePool使用场景

在for循环中alloc图片数据等内存消耗大的场景(需要创建很多临时对象),可以手动插入AutoreleasePool。

7.1、自动释放池代码转换

代码转换

objc_autoreleasePoolPush代码

objc_autoreleasePoolPush

objc_autoreleasePoolPop代码

objc_autoreleasePoolPop

7.2、自动释放池数据结构

7.2.1、概念
数据结构

双向链表

双向链表


7.2.2、AutoreleasePoolPage结构
AutoreleasePoolPage

由上面可以看到:AutoreleasePool是和线程一一对应的

AutoreleasePoolPage内存地址:

内存地址
7.2.3、AutoreleasePoolPage::push实现
AutoreleasePoolPage::push

AutoreleasePoolPage::push相当于是在当中插入哨兵对象,做标记。

7.2.4、[obj autorelease]实现过程
autorelease 调用autorelease
7.2.5、AutoreleasePoolPage::pop
AutoreleasePoolPage::pop

相当于是将next指针哨兵对象之间的内容,全部release。

发送release消息 next指针回退

7.3、自动释放池总结

总结

八、循环引用

8.1、循环引用类型

循环引用类型

8.2、场景

场景

8.3、破除循环引用思路

思路

8.4、循环引用方案

方案
  • __weak破解


    __weak
  • __block破解


    __block
  • __unsafe_unretained破解


    __unsafe_unretained

8.5、循环引用示例

8.5.1、 Block示例

参考Block示例

8.5.2、 NSTimer示例

先来解释为什么NSTimer能够产生循环引用?


NSTimer

1、因为对象拥有NSTimer,所以要对其强引用。
2、因为NSTimer持有它的target,所以NSTimer强引用对象。
3、通过对象弱引用NSTimer,达不到目的。
因为主线程的Runloop,长驻内存➡️Runloop强引用NSTimer➡️NSTimer强引用对象➡️所以当前对象很难释放

解决方案:

  • 非重复性定时器
//取消定时器
[timer invalidate];
timer = nil;
  • 重复性定时器


    重复性定时器

    设置中间对象,判断中间对象所持有的目标对象是否为nil(这里利用到了weak指针会自动为nil)。如果为nil,则执行以下代码:

//取消定时器
[timer invalidate];
timer = nil;

九、内存管理总结

问题11:什么是ARC?

ARC是由LLVM编译器和Runtime共同协作,为我们实现自动引用计数管理。

问题12:苹果是如何实现AutoreleasePool的?

是以栈为节点通过双向链表的形式组合而成。

问题13:什么是循环引用?你遇到过哪些循环引用,是怎样解决的?

上面讲的NSTimer例题就可以。

相关文章

  • 内存管理

    一.内存基本介绍 1、OC内存管理的基本概念 2、OC内存管理的范围​管理范围:管理任何继承自NSObject的对...

  • 内存管理

    目录一、内存分区 1、RAM和ROM 2、内存的五大分区二、内存管理 1、OC内存管理是指什么?OC内存管理的本质...

  • Lesson 0-1 Objective-C basic

    6.OC 手动内存管理 OC 内存管理原则: 只要使用 alloc, new, copy, mutableCopy...

  • OC的内存管理

    1、OC的内存管理 OC是通过引用计数进行内存管理的,其核心思想遵循“谁创建谁释放;谁引用谁管理”。 OC的内存管...

  • iOS之从MRC到ARC内存管理详解

    概述 在iOS中开发中,我们或多或少都听说过内存管理。iOS的内存管理一般指的是OC对象的内存管理,因为OC对象分...

  • iOS五大块知识总结之内存管理

    1.1 管理的原因 只有OC对象才需要管理内存,非OC对象(如:char、int、folat)则不需要管理内存的本...

  • iOS 中堆和栈的区别以及冒泡排序

    在引入堆和栈之前,先要知道,iOS中的内存管理范围: OC对象需要进行内存管理,非oc对象不需要进行内存管理,比如...

  • OC的内存管理

    最近系统地复习了OC的内存管理,所以总结下. OC是通过引用计数(reference count)来管理内存.自...

  • OC关于在MRC模式下的内存管理学习

    内存管理 管理范围 任何继承NSObject的对象 只有OC对象才需要进行内存管理的本质原理 1.OC对象在堆中 ...

  • 《Effective Objective-C 2.0》读书笔记(

    第五章 内存管理 第29条:理解引用计数 OC 中有手动内存管理(MRC) 自动内存管理(ARC)手动内存管理需要...

网友评论

    本文标题:OC内存管理

    本文链接:https://www.haomeiwen.com/subject/eqprmctx.html