iOS 内存管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 内存管理相关的知识,希望对你有一定的参考价值。

一 . 内存管理 包括内存分配 和 内存清除

 

1.内存管理的范围 :人和继承于NSObject类的对象都需要进行内存管理,任何非对象类型的对象(基本数据类型 如 int char float double struct enum等)

 

2.为什么只有OC对象才需要进行内存管理?

OC对象放在堆里面 非OC对象(基本数据类型 如 int char float double struct enum等)一般放在栈里面,栈内存会被系统自动回收

 

3.堆和栈

栈(操作系统):有系统自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈(先进后出)

堆(操作系统):一般由程序员手动分配释放,如果程序员不释放,程序结束时就会被系统回收,分配方式类似于链表

 

4.引用计数器

每个OC对象都有自己的引用计数器 从字面上可以理解成”对象被引用的次数” 也可以理解为有多伤风人正在使用这个对象

引用计数器的作用:引用计数器表示当前有多少人正在使用这个对象 到没有任何人在使用这个对象时系统就会回收这个对象 也就是说当对象的引用计数为0时,对象占用的内存就会被系统回收.如果系统的引用计数不为0那么在整个程序运行过程中,他占用的内存就不可能被回收(除非整个程序以经推出)

任何一个对象在刚创建的使用引用计数都为1 当使用 alloc init copy 等创建对象时,对象的引用计数默认为1

 

5.如何操作引用计数器

给对象发送一个 retain 消息 可以使引用计数器的值 +1

给对象发送一个 release 消息 可以使引用计数器的值 -1 ,release 并不代表销毁\回收对象 仅仅是引用计数值 -1

给一二对象发送 retainCount 消息 可以得到当前对象的引用计数器值 有时候不准确 很少用 因为常出错

需要注意的是: release 并不代表销毁\回收对象 仅仅是引用计数值 -1 只有当引用计数器值减到0 就会释放

 

6.dealloc方法

当一个对象的引用计数器为0时,这个对象即将被释放,其占用的内存被系统回收

对象即将被销毁时系统会自动给对象发送一条dealloc消息(因此,从dealloc方法有没有被调用.就可以判断对象是否被销毁) 

dealloc函数是系统调用的函数.不可程序员直接调用.一般情况下,会重写dealloc方法来释放相关资源,重写的dealloc方法就相当于对象的遗言,用来处理对象销毁后的一些后事.一旦重写了dealloc方法,就必须调用 [super dealloc] 并且放在dealloc方法的最后调用.

注意事项:dealloc方法是系统调用的方法,程序员不可直接调用,需要重写dealloc方法.一旦对象被回收,它占用的内存就不可再用,如果坚持使用就会导致程序崩溃(野指针错误)

 

 

二 .MRC(Manual Reference Counting) :所有的对象需要程序员手动管理,需要程序员自己编写release/retain等方法

 

1.内存管理的原则 :有加就有减  一次alloc就有一次release  一次retain就有一次release

 

2.野指针 空指针 僵尸对象

僵尸对象 : 只要一个对象引用计数为0 被释放 就称这个对象为僵尸对象

 

野指针 : 当一个对象指向僵尸对象,我们就成这个指针为野指针 (一个指针指向的对象的引用计数值为0 则这个指针为野指针).只要给野指针发送消息就会报错 EXC_BAD_ACCESS

 

企业开发中 一定要开启对僵尸对象的监听

 

空指针 : 为了避免给野指针放消息会报错,当一个对象被释放后我们会将这个对象设置成空指针nil/0. 因为给空指针发送消息不会报错.

 

3.多对象的内存管理

如果要在A对象和B对象中用C对象 一定要在A对象和B对象中对C对象进行一次retain 当A和B用完后也要对C进行release 一般情况下,A和B对C的retain放在A和B对C的调用函数中,A和B对C的release放在dealloc方法中.其余的A B C 的自释放都在原来的主函数中.

就像好几个人进一个游戏大厅打游戏,每进去一个人都要让大厅记录+1,当有人离开时,大厅里人数就会-1.当大厅里人数纪录为0时,就大厅释放.只要还有人,哪怕是一个人也不能释放大厅.

 

[email protected]修饰符

readonly:只生成getter方法

readwrite:同时生成getter/setter方法,默认情况下不写就是readwrite

 

getter:可以给生成的gutter方法起名称

setter:可以给生成的setter方法起名称 

 

retain:会自动帮我们生成setter/gettter方法内存管理的代码

assign:不会替我们生成setter方法的内存管理方法,仅仅只是生成普通的gettter/setter方法,默认什么都不写就是assign

 

[email protected]

@class 可以简单地引用一个类,就是告诉系统这是一个类,可以放心大胆的使用.

具体使用中,在 .h 文件中使用 @class, 在 .m 文件中使用 #import包含这个类的 .h 文件. @class 不拷贝这个类只是告诉编译器这是一个类,可以使用. #import 会拷贝累的头文件.

 在用到 @class 时,在 .h 文件里 @class,同时在 .m 文件里也要 #import,不可省略.

对于循环以来的关系使用@class可以避免死循环,因为 .h 文件中的 @class 不做任何拷贝, .m 文件中的 #import 只会拷贝对应的文件,不会形成死循环.

 

6.循环retain

如果A对象要拥有B对象,且B对象也要拥有A对象.此时就会形成循环retain

解决办法:让其中一方不要做retain操作

 

7.autorelease

只要给一个对象发送autorelease消息,就会将对象放到一个自动释放池中,当自动释放池销毁时,会对池子里面的所有对象做一次release操作. 

注意:这里只是发送autorelease消息,如果当时的引用计数值为0,则对象销毁,否则对象不会被释放. 调用完autorelease方法后,对象的引用计数值不会改变

autorelease的原理:autorelease实际上只是把对release的调用延迟了,对于每个autorelease系统只是把对象放到当前的自动释放池中,挡自动释放池被释放时,该吃中的所有对象都会被release

 

三.ARC(Automatic Reference Counting) : 不需要程序员管理内存,编译器会自动给程序议案家release/retain等代码

 

1.注意点

ios中的ARC和java中的垃圾回收机制不同.iOS中的ARC是编译器在编译阶段自动识别添加release/retain等方法带代码中在执行代码;java中的垃圾回收机制是系统在运行程序是定时检测垃圾并回收,是系统做的.

 

2.ARC的判断原则 

使用ARC时只要还有一个强指针变量指向对象,对象就会保持在内存中

强指针:被__strong修饰的指针,如果没有修饰词,默认的情况下都是强指针,强指针指向的对象会一直保存在内存中

弱指针:被__weak修饰的指针 ,弱指针指向的对象在创建完成后会立即被释放,无法保存

 

3.ARC中的循环引用

在ARC中如果A拥有B,B拥有A,一个用strong 一个用weak,必须有一方使用弱指针 

 

4.ARC中@property参数

strong : 用于OC对象,相当于MRC中的retain

weak : 用于OC对象,相当于MRC中的assign

assign : 用于基本数据类型,相当于MRC中的assign

 

以上是关于iOS 内存管理的主要内容,如果未能解决你的问题,请参考以下文章

IOS内存管理机制

iOS OC08,09_内存管理

iOS内存管理

iOS之内存管理(ARC)

iOS 中的内存管理

iOS 中的内存管理