objective-C内存管理学习笔记

Pro Multithreading and Memory Management for iOS and OS X是iOS与OSX平台开发者的神书之一不解释,适合时常翻阅,虽然说ARC时代对于内存管理开发者不需要过多的参与,编译器帮我们做了绝大多数工作,但是适当的理解还是非常有必要的,我自己也遇到过一些诡异的bug是因为内存管理不当造成的,同时感觉内存管理这块也是面试时候的重点哈哈哈哈所以有必要深入了解一下.
这本书分三章:内存管理,Block,GCD,花了一段时间把内存管理篇读完了,写点总结权当巩固一下知识.

1.引用计数

不同于java等语言的垃圾回收机制,苹果引入了引用计数的改变,简单的理解就是一个对象被人持有的时候,引用计数retainCount + 1,这个引用关系没有的时候就-1,当引用计数为0的时候则认为对象没有被人持有,就释放掉这个对象了.一般当我们调用alloc,new,copy,mutableCopy开头的方法的时候我们自己都会持有这个对象,自己可以持有自己生成的对象,同时也能够持有别人生成的对象,比如:

    //obj持有自己生成的对象
    id obj = [[NSObject alloc] init];
    //obj2持有obj这个对象
    id obj2 = obj;

2.ARC 自动引入计数

顾名思义,自动引用计数(相对于MRC手动引用计数),是Xcode的编译器特性之一,编译器会在适当的时候帮我们插入内存管理代码(不是这么简单还有其他一些复杂的优化操作),让我们避免了花费大量精力去考虑内存管理.
先了解一下对象的所有权修饰符,在ARC环境下,有四种所有权修饰符:

  1. __strong
  2. __weak
  3. __unsa__unretained
  4. __autorelease

我们平时这样定义一个属性:

@property(nonatomic, strong) UIView *view;

其中的strong就是内存管理关键字,实际上我们在定义属性的时候使用的strong/weak/assign等都是被转化成这些修饰符,下面是对应的转化关系:

assign            ------> __unsafe__unretained修饰符
copy              ------> __strong修饰符(赋值的是被复制的变量)
retain            ------> __strong修饰符
strong            ------> __strong修饰符
unsafe_unretained ------> __unsafe__unretained修饰符
weak              ------> __weak修饰符

使用以上关键字就相当于直接给属性加上了对应的修饰符,copy除外,copy赋值是通过copyWithZone:方法复制源对象的修饰符.

2.1 __strong修饰符

__strong是强引用的意思,它是id类型跟对象类型的默认修饰符,也就是说默认会加上__strong修饰符,除非你去显式的指定__weak等修饰符,这种修饰符修饰的对象会在超出它的作用域的时候释放掉,或者说如果是通过另外一个强引用对象赋值产生的强引用,会在它引用的对象为nil的时候释放掉.
__strong,__weak,__autoreleasing这三种修饰符可以保证对象在初始化的时候把对象初始化为nil,这一点是跟__unsafe__retained很大的不同.

2.2 __weak修饰符

id __weak obj = [[NSObject alloc] init]
__weak是iOS5之后新增的,即为弱引用,它是为了解决__strong修饰符导致循环引用来引入的,所谓循环引用就是A,B对象相互引用,就很容易发生了内存泄露,当然还有更罕见的A对象自己持有自己导致的循环引用.
弱引用不能持有一个实例对象,刚才的那句代码对象会立即释放,因为弱引用不持有对象,所以在对象超过作用域的时候就会立刻把对象释放掉,于是就打破了引用循环.
weak还有一个好处,当一个对象释放掉的时候,会立刻把对象置nil(assign对应的修饰符是__unsafe__unretained则不会).
weak实现
__weak修饰符的实现其实比较复杂,当我们初始化一个weak修饰的对象,运行时是调用objc_initWeak(&obj1,obj),obj1是我们初始化对象后赋值的对象,obj则是该对象本身,这个函数会继续调用objc_storeWeak(&obj1, obj)函数,然后把第二参数obj作为key,第一参数&obj1作为value存储到weak表中,这样的话在废弃对象的时候通过将要废弃的对象的地址作为键值从表中查询就能够快速的查找到对应的对象了.
weak销毁
然后在对象作用域结束,就调用了销毁函数objc_destoryWeak(&obj1),这个函数具体会做哪些事呢?

(1). objc_release  
(2). 引用计数为0,执行dealloc  
(3). _objc_roowDealloc
(4). object_dispose  
(5). objc_destructInstance  
(6). objc_clear_deallocating  

其中最后一个函数objc_clear_deallocating又会做以下操作:

a. 从weak表中通过废弃对象的内存地址查找记录  
b. 将查找到的所有__weak修饰的记录的地址赋值为nil.  
c. 从weak表删除记录  
d. 通过废弃对象的地址从引用计数表中查找到记录并且删除.  

我们可以看到,通过这些操作,__weak修饰的对象在销毁的时候就能赋值为nil了,但是同时我们也应该看到使用weak是比较消耗cpu资源的,所以我们应该避免过多使用weak,而仅仅使用它来避免循环引用,这也是实现weak的目的所在.

2.3 __unsafa__unretained修饰符

这玩意可以翻译为不安全不持有的修饰符,反正我是开发工作中是没有接触到过,它跟weak相同的是都不持有对象,所以生成的对象会立刻被释放掉.

2.4 __autoreleasing修饰符

在ARC下不能用NSAutoreleasePool来创建自动释放池,可以通过@autoreleasepool(没错就是程序入口的那玩意)来创建,使用了这个修饰符类似于在MRC下调用了autorelease方法.
还记得我们开头说的调用alloc,new,copy,mutableCopy方法会持有生成的对象么?那么当我们不是通过这些方法创建的对象呢?比如:

id obj = [NSArray array];

事实是如果编译器检查到对象不是通过以上四个方法创建的,会自动把这个对象注册到autoreleasepool,那么自动释放池里面的对象会什么时候释放呢?这里其实牵扯到runloop的知识,自动释放池会注册到runloop中,可以把runloop理解为一个不停开始-休眠-开始的循环,当本次循环执行完毕,下次循环开始的时候如果检测到对象没被引用就会释放这个对象(更多runloop相关内容可以看百度知道团队的runloop视频).
再回到weak,其实在访问__weak修饰的对象的时候,实际上必定会访问注册到autoreleasepool的对象.这句话怎么理解呢?
因为weak是弱引用,所以在访问的时候有可能对象已经被废弃了,所以苹果的做法是通过把要访问的对象注册到autoreleasepool中,在@autoreleasepool{}结束之前都能确保对象一直存在咯.

以上是自己读书下来的一些笔记,大致大致总结了一下各种关键字底层做了些什么,有错误的地方欢迎指出,后续再有新的心得会在这个博客下面继续记录下来~~

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

推荐阅读更多精彩内容