引用计数是一个简单而有效的管理对象生命周期的方式。不管是oc还是swift,其内存管理方式都是基于引用计数的。当我们创建一个对象时他的引用计数是1,当有新的指针指向他那么引用计数加1,当某个指针不再指向他,那么引用计数减1,当对象的引用计数为0,那么对象立即释放。
Objective-C提供了三种内存管理方式:manual retain-release(MRC,手动管理),automatic reference counting(ARC,自动引用计数),garbage collection(垃圾回收)。iOS不支持垃圾回收;ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;
创建的对象(使用alloc,new,copy或者mutalbeCopy等方法)的初始引用计数是1,给对象发送retain消息后,你拥有了这个对象,引用计数加1,当你不需要使用该对象时,发送release或者autorelease消息放弃这个对象,引用计数减1;
对象属性内存管理:
下面是属性参数说明
属性参数表atomic参数基本不用;MRC下用retain和assign,在ARC下用strong和weak,retain和strong相似,weak和assign相似;
assign,用于基本数据类型
-(void)setA:(int)a{
_a=a;
}
retain,通常用于非字符串对象
-(void)setA:(Car *)a{
if(_a!=a){
[_a release];
_a=[a retain];
}
}
copy,通常用于字符串对象、block、NSArray、NSDictionary
-(void)setA:(NSString *)a{
if(_a!=a){
[_a release];
_a=[a copy];
}
}
自动释放池:
自动释放池和release的区别:
release会立刻递减对象的保留计数,可能令系统立即回收它,注意是可能。
自动释放池呢,假如自动释放池的对象,会稍后递减,这个稍后一般指下一次event loop的时候,注意这里是一般,不是说绝对。
自动释放池多用于跨方法调用,书上的原话说,自动释放池可以保证对象在跨越「方法调用边界」(method call boundary)后一定存活,实际上,释放操作会在清空最外层的自动释放池时执行,除非你有自己的自动释放池,否则这个时机指的就是当前线程的下一次事件循环。
自动内存释放使用@autoreleasepool关键字声明一个代码块,如果一个对象在初始化时调用了autorelase方法,那么当代码块执行完之后,在块中调用过autorelease方法的对象都会自动调用一次release方法。这样一来就起到了自动释放的作用,同时对象的销毁过程也得到了延迟(统一调用release方法)/****释放时机
1.释放操作是RunLoop管理的 要RunLoop运行到释放的时候才会被释放,RunLoopEnterwaiting的时候就释放了(在每一个事件周期(event cycle)的开始,系统会自动创建一个自动释放池;在每一个事件周期的结尾,系统会自动销毁这个自动释放池。一般情况下,你可以理解为:当你的代码在持续运行时,自动释放池是不会被销毁的,这段时间内你也可以安全地使用自动释放的对象;当你的代码运行告一段落,开始等待用户输入(或者其它事件)时,自动释放池就会被释放掉,池中的对象都会收到一个release消息,有的可能会因此被销毁。)
2.释放是统一处理的 不是某个对象为引用计数为0就把他立即释放了。
3.CoreFoundation对象和OC对象互转的释放问题 CF对象是不支持ARC的 要自己管理
***/
对于自动内存释放简单总结一下:
autorelease方法不会改变对象的引用计数器,只是将这个对象放到自动释放池中;
自动释放池实质是当自动释放池销毁后调用对象的release方法,不一定就能销毁对象(例如如果一个对象的引用计数器>1则此时就无法销毁);
由于自动释放池最后统一销毁对象,因此如果一个操作比较占用内存(对象比较多或者对象占用资源比较多),最好不要放到自动释放池或者考虑放到多个自动释放池;
ObjC中类库中的静态方法一般都不需要手动释放,内部已经调用了autorelease方法;
(aotoreleasepool到达底什么时候释放?是pool drain后就释放了吗?)
对于每一个Runloop, 系统会隐式创建一个Autorelease pool(自然会有多个Autorelease pool),这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。
那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 都会是一个新的Runloop
网友评论