移动设备的内存极其有限,每个App所占的内存也是有限的,当App占用内存较多时,会有内存警告。如果一个app使用的内存超 过20M,则系统会向该app发送Memory Warning消息。收到此消息后,需要回收一些不需要再 继续使用的内存空间,比如回收一些不再使用的对象和变量等,否则程序会崩溃。
1.OC的内存管理范围
可以管理任何继承NSObject的对象,对其他的基本数据类型无效。
本质是因为对象和其他数据类型在系统中的存储空间不一样,其他局部变量主要存放在栈中,而对象存放在堆中,当代码块结束时代码块中的所有局部变量都会被回收,指向对象的指针也会被收回,此时的对象没有指针指向,依然存在于内存中,会造成内存泄露。
2. OC内存管理的原理
(1)对象的所有权及引用计数
(2)对象的引用计数器:
每一个OC对象都有自己的引用计数器,是一个整数表示对象被引用的次数,对象刚被创建的时候,默认引用计数器值为1。
用引用计数器是判断对象要不要回收的依据,引用计数器不为0时,则对象存在。
(3)对引用计数器的操作
retain:计数器+1,返回对象本身;
release:计数器-1,但是并不代表对象被释放;
returnCount:当前对象的引用计数
(4)对象的销毁
当对象销毁时,系统会自动向对象发送一条“dealloc”方法,一般是重写这个方法,相当于是“临终遗言”
3. 内存管理分类
MRC、ARC、垃圾回收机制
4. 内存管理原则
(1)只要还有人在使用某个对象,那么这个对象就不会被回收;
只要你想使用这个对象,那么就应该让这个对象的引用计数器+1;
当你不想使用这个对象时,应该让对象的引用计数器-1;
(2)谁创建,谁release
(3)谁retain,谁release
5. 内存问题
(1)内存泄露
<1>在代码块结束之后,当对象的引用计数器值不为0的时候,会造成内存泄露;
<2>retain和release个数不匹配;
<3>对象使用的过程中,被赋值了nil;
(2)野指针
僵尸对象:已经被销毁的对象;为了防止不小心调用了僵尸对象,可以将对象赋值为nil
野指针:指向僵尸对象的指针
空指针:没有指向存储空间的指针(里面存的是nil, 也就是0) ,给空指针发送消息不会报错
6. set方法的内存管理
(1)存在的问题
原对象无法释放造成的内存泄露;
原对象能够释放,但是引起新的问题,set自己的时候,造成的野指针 ;
解决:
(1)判断新传递的对象是否是原来的对象,如果不是原来的对象则释放,然后再retain
-(void)setCar:(Car*)car{
//判断_car 存放的是否是 形参对象,如果不是,则执行[_car realease];
if (_car!=car) {
[_car release];//先释放上一个对象,(注意第一次是向nil发送release消息)
_car = [car retain];
}
}
(2)对于基本数据类型,直接赋值
-(void)setAge:(int)age
{
_age=age;
}
(3)OC对象类型
-(void)setCar:(Car *)car
{
//1.先判断是不是新传进来的对象
if(car!=_car) {
//2 对旧对象做一次release
[_car release];//若没有旧对象,则没有影响
//3.对新对象做一次retain
_car=[car retain];
}
}
7. @property参数
(1)
xCode 4.4前:@property帮我们生成get和set方法的声明我们自己实现get和set方法 @property和@synthesize联合@property ;
xCode 4.4后:@property int age; 1)生成一个_age 2)生成get和set方法的声明 3)生成get和set方法的实现;@property (......) int age;
(2)@property 有两个对应的词,一个是@synthesize,另一个是@dynamic;
如果 @synthesize 和@dynamic 都没写,那么默认的就是@syntheszie var = _var;
@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器 会自动为你加上这两个方法;
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生 成(当然对于 readonly 的属性只需提供 getter 即可)
假如一个属性被声明为@dynamic var,然后你没有提供@setter 方法和@getter 方 法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = instance.var 时,由于缺 getter 方 法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所 谓的动态绑定
(3)参数
参数类别 | 参数 | 说明 |
原子性 | atomic | 对属性加锁,多线程下线程安全,默认值 |
nonatomic | 对属性不加锁,多线程下不安全,但是速度快 | |
读写属性 | readwrite | 生成getter,setter,默认值 |
readonly | 只生成getter方法 | |
set方法处理 | assign | 直接赋值,默认值(适用于非OC对象类型) |
retain | 先release原来的值,再retain新值(适用于OC对象类型) | |
copy | 先release原来的值,再copy新值 |
8. 循环引用问题