iOS内存管理

1, 面试题

1, 使用NSDisplayLink、NSTimer有什么注意的地方?
2, 介绍下内存的几大区域?
3, 你对iOS内存管理是怎样理解的?
4, ARC都帮我们做了什么?
5, weakSelf的原理是怎样的?
6, autorelease对象会在什么时机调用release?
7, 方法里有局部变量, 会在方法执行完之后马上释放吗?

2, timer的探究

我们先从NSTimer开始讲起

2.1 NSTimer

使用NSTimer最常见的问题有两个: 一个在后面说, 另一个就是循环引用, 引起循环引用的原因是: NSTimer中有一个强引用的target属性, 持有VC本身, 所以会形成指针环. 解决的方案有:
1,调用带block的方法且配合weakSelf来达到弱引用的效果;
2, 使用一个第三方的中间体来达到弱引用的效果(proxy).
接下来我们先简单说一下方法1, 然后重点说方法2.
调用带block的方法且配合weakSelf来达到弱引用的效果


使用一个第三方的中间体来达到弱引用的效果(proxy)
这个方法的原理是这样的: 创建一个中间体来弱引用持有viewController, 从而达到破坏循环引用的目的

这个中间体我们一般称为proxy, 实现的方法有两种: 一种是继承自NSObject, 另一种方法是继承自NSProxy. 下面直接po出这两种方法的实现, 然后比对效果.
新建一个工程, 然后分别封装两个proxy类, 并实现调用, 代码截图如下

封装的代码如下, 注意截图中的提示


上面的代码就是实现的全部了, 可能也会有同学有疑问: 为什么不直接在GQProxy00或GQProxy01中实现test方法呢? 因为我们设计这个proxy中间体就是是为了考虑到以后别的类或者taget也会使用这个proxy做中间体, 所以proxy内部不写最终要调用的方法, 而是返回消息发送者本身.
接下来我们说一下继承自NSObject和NSProxy这两种不同方案的区别:
1, 继承自NSObject的中间体使用的是消息发送的整套机制, 也就是会遍历本身和父类的消息列表, 最终找到方法本身来进行调用;
2, 继承自NSProxy的中间体则直接使用消息转发机制, 也就是消息发送机制的最后一步, 直接将消息转发出去, 这样效率更高.
上面的第二点就是NSProxy类的最大用处. 关于NSProxy可能我们了解的很少, 下面展开说一下:
NSProxy是啥
NSProxy是一个跟NSObject同级的类, 遵守<NSProxy>协议但不继承自NSObject; 其本身并没有init方法; 当使用NSProxy的对象进行方法调用时, 并不会去遍历父类的方法列表, 而是只遍历本身的方法列表, 如果没找到方法实现, 则会直接将消息转发; 是一个专门设计用来进行消息转发的类, 相比于一般继承自NSObject的类, 其转发消息非常的高效.

刚刚没说的关于NStimer的一个问题就是: NStimer定时器并不能保证时间精准. 因为NStimer的底层是基于runloop来实现的. 实现的过程是这样的: 假如设置了NStimer时间间隔为1.0秒, runloop底层有一段计算时间的代码, 当runloop每进行一次循环都会判断累计的时间, 如果累计时间>=1.0s, 就会调用NStimer的方法. 但其实runloop每次循环的时间都是根据任务的不同而有所不同的, 这就是导致不能保证每次累计的时间间隔都能精确的控制在1.0s. 所以如果需要精准的时间间隔, 应该使用GCD, 因为GCD是不依赖runloop来实现的时间间隔, 而是依赖内核来实现的.

2.2 NSDisplayLink

相比于NStimer, NSDisplayLink也可以实现定时器功能, 但其可以精准的实现60fps帧率的水平, 也就是屏幕刷的帧率. 但其跟NSTimer一样, 也会对taget形成强引用, 引起循环引用, 而解决的方法跟NStimer一样, 所以这里就不展开说了.

接下来我们讲内存管理的另一块知识点: 内存布局.

3. 内存布局

4, tagged pointer

4.1 简介

看下面的介绍

在使用tagged pointer之前, 对象的存储是通过指针来指向的, 而在tagged pointer之后, 直接把对象存储在指针中, 示意图如下

如何判断一个指针是不是tagged pointer? 下面是runtime的源码

下面我们来看一个面试题.

4.2面试题


下面我们直接说结果吧:
第一个for循环会直接报错崩溃, 而且是地址错误. 为什么呢? 主要原因有两个:
1,第一个跟tagged pointer相关. 在这里, 由于字符串比较长, 所以第一个name会被runtime设置成非tagged pointer, 开启多线程频繁访问name的时候, 在底层不停的[_name release]和_name=[name copy]的时候, 由于没有加锁, 所以可能会导致不同线程间销毁原对象导致野指针错误;
1, 第二个跟线程相关, 就是上面提到的多线程读写操作.
如果要解决这个问题, 就需要我们在name属性前加atomic修饰, 而不是nonatomic. 或者对dispatch_queue进行信号量限制为1.
第二个for循环不会报错, 因为第二个name的字符串很短, runtime会将其设置成tagged pointer, 就不会存在上面的问题, 读写值都非常高效.

5, 对象的内存管理

5.1MRC

5.2 copy

一般调用copy的目的是为了获得一个副本对象, 当修改副本对象或者修改原对象的时候, 相互之间不影响. copy可分为深拷贝和浅拷贝, 深拷贝是产生了新的对象并分配了新的内存地址, 浅拷贝则只是拷贝了指针指向原对象地址, 原对象和地址都没有改变. 下面表格是拷贝的总结:其规律就是对象和拷贝返回的对象不一致时候, 就需要深拷贝

另外需要注意的两点是:
1, 用copy修饰的属性, 编译器编译后会在底层的setter方法内部调用copy方法, 所以一般NSMutabelArray、NSDictionary等可变对象都不建议使用copy来修饰, 否则很容易在后续代码中修改值的时候引起崩溃, 而且xcode也没有提示警告;
2, 自定义的类如果想要调用copy方法, 则必须遵守<NSCopy>协议并且实现initWithZone:方法, 并且在方法中写明需要copy的对象属性等.

5.3weak指针的原理

直接总结如下:
1,当一个对象被weak指针指向的时候, runtime会以这个对象的地址值作为key保存到sideTable类中的weak_table散列表中对应的weak指针数组里;
2, 当对象调用dealloc方法时候, 就会以对象地址作为key, 从sideTable的weak_table散列表中的weak数组遍历逐个把weak设置为nil.

6, 自动释放池aotoreleasepool

先看截图吧



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容