ios内存管理

                                               ios内存管理

一.前言

在ios中,系统对每个程序运行时内存的占有都有一个限制,默认都是几十兆左右,当程序占用内存的大小超过限制时,程序可能就会被强制退出.

在内存中,分为堆和栈,栈中主要存放变量,堆中主要存放对象。栈中的东西是系统自动收回的,当一个变量使用完成后,存放在栈中的东西会立即被收回。但堆中存储的东西是不会被随便回收的。

由于移动设备内存有限,所以我们会对内存进行严格的管理,以避免内存泄露造成资源浪费。

在OC中,只有对象才属于内存管理范围,例如int ,float,struct等基本数据类型不存在内存管理的概念,在ios开发中,对内存的管理实际上是对引用计数器的管理

相关概念:

僵尸对象:所占用的内存被回收的对象,僵尸对象不能再使用。

野指针:指向僵尸对象的指针,给野指针发消息会报错。

空指针:没有指向任何东西的指针,给空指针发送消息不会报错。


目前OC内存管理方式有三种:

(1)自动垃圾收集(Automatic Garbage Collection)

(2)MRC(Manual Reference Counting,手动引用计数器)和自动释放池(Autorelease)

(3)ARC(Automatic Reference Counting,自动引用计数器)

自动垃圾收集:

在OC2.0中,有一种自动垃圾收集的内存管理形式,通过垃圾自动收集,系统能检测出对象是否拥有其他对象,当程序运行期间,不被引用的对象就会被释放。

但是在ios运行环境中不支持自动垃圾收集,在OS X环境才支持,不过苹果推荐使用ARC进行替代。

MRC和自动释放池子:

  1. 引用计数器的概念:

即一个对象被引用的次数,每个对象的引用计数器占4个字节。

说明当一个对象被创建的时候,该对象的默认RC为1,当该对象被引用一次,需要调用retain方法,使RC的值加1,当指针失去对该对象的引用,需要调用release方法,使RC的值减1,当RC的值等于0时,该对象被系统自动销毁回收

2.对象的销毁

  当一个对象的RC为0时,那么它将被销毁,其占用的内存会被系统回收.

  当一个对被销毁时,系统会自动向对象发送一条dealloc消息

  一般会重写dealloc方法,在这里释放相关资源,dealloc就是对象的遗言 

  一旦重写了dealloc方法,就必须调用[super dealloc],并且放在最后面调用

  对象一旦被回收了,它占用的内存不再可用,坚持使用就会导致指针错误

3.MRC

通过人为的方式来控制引用计数器的增减,影响对象RC值的方式有以下几种:

(1)new, alloc,copy,mutableCopy这几种方式来创建一个新的对象,此时RC的默认值为1.

(2)retain,对象调用retain方法,RC的值加1.

(3)release,对象调用release方法,RC的值减1.

(4)dealloc,dealloc方法并不会影响RC值,但是当RC值为0时,系统会调用dealloc方法来销毁对象.

例如:

通过上面代码我们知道,成员变量的设值和取值方法是手动生成的,而且setter方法中成员变量的引用计数器也是手动设置,我们可以通过@property和相应关键字来由编译器生成.

关于在MRC中@property关键字如下:

(1)assign和retain和copy

这几个关键字用于setter方法的内存管理,如果使用assign(一般用于非OC对象),那么将直接进行赋值操作;如果使用retain(一般用于OC对象),那么将retain新值,release旧值;如果使用copy,那么将release旧值,copy新值。

(2)nonatomic和atomic

这两个关键字用于多线程管理,nonatomic的性能高,atomic的性能低.不显示则atomic为默认值

(3)readwrite和readonly

这两个关键字说明是否生成setter方法,readwrite将自动生成setter方法和getter方法。readonly则只生成getter方法

如果使用@property属性,上述代码可以改为:

4.循环引用内存管理原则

对于两个类B包含A,A包含B的循环引用情况下,看如下代码:

当执行Book*b1=[[Book1 alloc]init]后;b1指向Book1。

当执行Book2*b2=[[Book2 alloc]init]后,b2指向Book2。

当执行b1.book2=b2后;Book1中的成员变量_book2指向Book2。

当执行b2.book1=b1后;Book2中的成员变量_book1指向Book1。

此时Book1的引用计数器RC=2;Book2的引用计数器RC=2。

当执行[b1 release]后,b1释放对Book1的控制权,此时Book1的引用计数器RC=2-1=1。

当执行[b2 release]后,b2释放对Book2的控制权,此时Book2的引用计数器RC=2-1=1。

那么由于仍有指针指向Book1和Book2,所以Book1和Book2不会被销毁释放,这样就造成内存泄露.

对于上面的情况,只需要在Book1或者Book2的任意一端使用assign,如此就能避免互相引用。

对于下面这种循环引用情况,只能使用assign。

如果@property(nonatomic,assign)id instance中的assign换成retain,也会造成内存泄露,因为id为泛型。

5.Autorelease Pool的使用

顾名思义,Autorelease即自动释放对象,不需要我们手动释放。从上面的代码中可以知道,在main函数中,创建对象obj后,总需要调用[obj release]方法,这样无疑工作量变大,且对我们的工作无多大意义。为了减少这种无意义的工作,我们可以使用Autorelease Pool。

在ios程序运行的过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出),当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池。

Autorelease Pool即自动释放池,在Autorelease Pool内的对象,其release方法最终由编译器自动完成,而不需要手动执行。

autorelease的具体使用方法:

(1)生成并持有NSAutoreleasePool对象

(2)调用已分配对象的autorelease实例方法

(3)废弃NSAutoreleasePool对象

那到底什么时候废弃NSAutoreleasePool对象呢?

在Cocoa框架中,相当于程序住循环的NSRunLoop或者在其他程序可运行的地方,对NSAutoreleasePool对象进行生成、持有、和废弃处理。如下图:

NSAutoreleasePool对象的生命周期如下:

NSAutoreleasePool的创建有两种方式:

在返回对象的方法中最好使用自动释放池释放对象,由于在返回该对象之前不能释放该对象,所以可以通过自动释放池来延迟该对象的释放。如:

如果在一个循环中产生了大量的临时对象,可以在循环的内部提供一个自动释放池在下一次迭代前来清除这些对象,以减少最大内存占用。


6.ARC

ARC是编译器特性,可以理解为xcode的功能。它主要用来帮用户做内存管理工作,优化开发流程。

特别注意的是它与java的垃圾回收机制不是同一个东西,它仅是xcode的一个功能而已。在ARC下,RC由编译器自动管理,不需要手动管理。

ARC判断标准:

只要没有强指针指向该对象,该对象就会被释放。就算此时有弱指针指向该对象,或者该对象还指向其他对象,只要没有强指针指向其,其仍旧被释放。

ARC特点:

(1)不允许调用release、retain、retainCount

(2)@property的参数

*strong:成员变量是强指针(适用于OC对象)

*weak:成员变量是弱指针(适用于OC对象)

*assign:适用于非OC对象

(3)MRC下的retain改用strong

在实际项目中,某些文件需要用到release,retain方法,比如下载的第三方框架中如果有release方法,放在支持ARC的环境下会报错。这时我们可以设置这些文件不使用ARC,其他支持ARC环境的文件继续使用ARC,相应的方法是选择项目的Build phases,在Compile Sources中选择不需要ARC的文件,双击或回车,在弹出的窗口中输入-fno-objc-arc即可。同理可在MRC环境中使用-f-objc-arc使相关文件支持ARC.

ARC模式下,创建新对象通常由以下几种关键字来限定。

(1)_strong(默认值),由_strong修饰的为强指针,对象只要有强指针指向它就不会被销毁,每当一个强指针指向它,该对象的RC+1。

(2)_weak,由_weak修饰的为弱指针,弱指针指向的对象不会影响该对象的RC值,当弱指针指向的对象被销毁时,该指针的值为nil(即该指针指向一个nil对象)。

(3)_unsafe_unretained,该类型指针不会影响所指对象的RC值,当其所指向的对象被销毁时,该指针的值不会变为nil,仍保留原有的地址(即仍然指向已被释放对象的地址,因此才会_unsafe)。

注意:ARC模式下仍能使用自动释放池。

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