引用计数器
当一个对象被创建出来,就要分配给内存这个对象,当不用这个对象的时候,就要及时的回收,为了可以明确知道对象有没有被使用,就要用引用计数器来体现,只要计数器不为0,表明对象被使用中。
1.方法的基本使用
1> retain :计数器+1,会返回对象本身
2> release :计数器-1,没有返回值
3> retainCount :获取当前的计数器
4> dealloc
* 当一个对象要被回收的时候,就会调用
* 一定要调用[super dealloc],这句调用要放在最后面
2.概念
1> 僵尸对象 :所占用内存已经被回收的对象,僵尸对象不能再使用
2> 野指针 :指向僵尸对象(不可用内存)的指针,给野指针发送消息会报错(EXC_BAD_ACCESS)
3> 空指针 :没有指向任何东西的指针(存储的东西是nil、NULL、0),给空指针发送消息不会报错
常见错误:
EXC_BAD_ACCESS : 访问了一块坏的内存(已经被回收、已经不可用的内存
-[Person setAge:]: message sent to deallocated instance 0x100109a10
给已经释放的对象发送了一条-setAge:消息
set方法内存管理
如果一个指针指向一个新创建出来的对象,对象的计数器会加1,当指针又指向了一个新的对象的时候,原来的对象占用的内存就应该要及时的释放,这个时候就需要对set方法重写,对对象的计数器做一次管理
- (void)setCar:(Car *)car { if (car != _car) { // 对当前正在使用的车(旧车)做一次release [_car release]; // 对新车做一次retain操作 _car = [car retain]; } }
说明:基本数据类型不需要管理内存
在对象被回收的时候会自动调用dealloc方法
- (void)dealloc { [_car release]; [super dealloc]; }
内存管理代码规范:
只要调用了alloc,copy,必须有release(autorelease)
对象不是通过alloc或者copy产生的,就不需要release
autorelease和autoreleasePool
1.autorelease的基本用法
1> 会将对象放到一个自动释放池中
2> 当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
3> 会返回对象本身
4> 调用完autorelease方法后,对象的计数器不变
2.autorelease的好处
1> 不用再关心对象释放的时间
2> 不用再关心什么时候调用release
3.autorelease的使用注意
1> 占用内存较大的对象不要随便使用autorelease
2> 占用内存较小的对象使用autorelease,没有太大影响
4.错误写法
1> alloc之后调用了autorelease,又调用release
@autoreleasepool { // 1 Person *p = [[[Person alloc] init] autorelease]; // 0 [p release]; }
2> 连续调用多次autorelease
@autoreleasepool { Person *p = [[[[Person alloc] init] autorelease] autorelease]; }
5.自动释放池
1> 在iOS程序运行过程中,会创建无数个池子。这些池子都是以栈结构存在(先进后出)
2> 当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池
说明:
1.autorelease方法会返回对象本身
2.调用完autorelease方法后,对象的计数器不变
3.autorelease会将对象放到一个自动释放池中
4.当自动释放池被销毁时,会对池子里面的所有对象做一次release操作