什么是内存管理?????
换句话就是对内存地址的操作。程序在运行的过程中通常以下行为,都会使程序占用内存。
1. 创建一个OC对象
2.定义一个变量
3.调用一个函数或者方法
通常我们买手机都要关注下,手机的内存、运行内存等参数,那是因为我们手机的内存是一定的,超出手机内存,会导致手机崩溃,死机等状况。平时我们玩手机都是开着多个软件,所以需要对软件的占用内存进行管理。
程序中占用的内存超出,系统会发出警告,这时需要程序对现在暂时不需要的内存空间(不使用的对象、变量)回收。
SO 对内存进行合理的分配内存、清除内存、回收没有使用的对象,保证程序的稳定性。
开发工程中,那些才需要我们进行内存管理?????
一、任何继承了NSObject的对象需要进行内存管理
二、其他非对象类型(int char float double struct enum等)不需要手动内存管理
操作系统的内存是堆 和 栈两种形式
堆一般是程序员分配和释放的内存地址空间----手动内存管理MRC
栈是系统自动分配和释放的内存地址空间----自动管理内存ARC
内存的管理原则,谁分配,谁管理(释放)
ARC我们一般不做任何操作
MRC需要我们管理,管理得有个标准(参考)。
MRC通过引用计数器来判断这个对象是处于使用状态,还是处于释放状态。
当对象刚创建时,引用计数为1
使用一次alloc、new、copy创建对象时,引用计数为1
当没有人使用这个对象时,系统回收这个对象,从引用计数判断,引用计数为0,改对象占用的内存会被系统回收。
引用计数器的操作
为保证对象的存在,需要对对象发送(调用)一条retain(返回对象本身)消息,引用计数+1
不在使用对象时,通过发送(调用)release消息,引用计数 -1
对象通过调用(发送)retainCount消息 获得该对象当前引用计数
当前引用计数 =0,系统自己会释放内存,自动发送(调用)dealloc消息 这是销毁/回收对象 需要注意下release只是对引用计数的操作,对对象没有任何作用,不是它销毁对象的
另外注意下,对象发送dealloc消息时,必须调用super dealloc,还用就是该对象的内存地址进行其他操作,强行操作会使程序崩溃,该内存地址也成为野指针。
野指针和空指针
只用对象被释放,我们这个对象为僵尸对象(不能使用对象)
当一个指针指着一个僵尸对象,我们称这个指针为野指针
只要野指针发送消息就会报错(程序崩溃)
避免出现野指针,给该对象置空。
自动释放池(自动管理 除了这池,这池里的对象全部释放,回收空间)
autorelease是一种支持引用因数的内存管理方式,只要对象发送autorelease消息,该对象就会放在一个自动释放池中,当自动释放池被销毁时,池中小鱼(对象)全部清洗掉。特殊情况如果小鱼引用计数-1 之后,引用计数不为0,这个小鱼学了分身术,不会被释放
自动释放池的特别之处:不需要关心对象释放的时间,不用关心什么时候调用release
autorelease本质还是对象调用release方法(延迟),只是有个标记,池的标记,在池内,对象一直存在,在池外就没用这个标记,就是释放
注意事项
并不是放到自动释放池中,该对象就要遵守自动释放池准则,需要该对象发送autorelease消息
自动释放池外面发送autorelease消息,不起任何作用
自动释放池中不适合放占用内存比较大的对象
大量循环操作放到同一个autoreleasepool中,会造成内存峰值的上升
不能连续使用autorelease
使用了autorelease release 两个不能连续使用
MRC避免使用死循环
定义两个类Person类和Dog类
#import
@class Dog;
@interface Person : NSObject
@property(nonatomic, retain)Dog *dog;
@end
#import
@class Person;
@interface Dog : NSObject
@property(nonatomic, retain)Person *owner;
@end
执行以下代码:
int main(int argc, const char * argv[]) {
Person *p = [Person new];
Dog *d = [Dog new];
p.dog = d; // retain
d.owner = p; // retain assign
[p release];
[d release];
return 0;
}
就会出现A对象要拥有B对象,而B对应又要拥有A对象,此时会形成循环retain,导致A对象和B对象永远无法释放
那么如何解决这个问题呢?