学习要点:
1. Reference Counting引用计数机制
2. 了解MRC,APC和GC
3. AutoreleasePool运行机制
4. 如何避免Retain cycle
Reference counting引用计数机制
Cocoa上基本的内存管理机制就是引用计数,通过一个reference count(retainCount)来计数,有一个引用就加1,释放就减1,reference count为0,就释放对象。
如果需要持有一个对象,那么对其发送retain,如果之后不再使用该对象,那么需要对其发送release(或者autorealse),每一次对copy,retain,alloc或者new的调用,需要对应一次release或autorealse调用。
常用关键词
alloc就是开辟一块内存,引用计数为1
new是较为老式的写法,后来引入了alloc +init这种写法,可以把分配内存和初始化操作分开。
assign就是直接赋值,引用计数不变,当数据为int, float等原生类型时,可以使用assign。
retain引用计数加1,返回一个引用。
release引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。
copy复制内容,在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。
nonatomic/atomic表示该属性是否是对多线程安全的,atomic会自动加线程锁,但效率较差,默认为atomic
什么是MRC,APC和GC
Cocoa上有三种内存管理机制,MRC,APC和GC,GC由于效率问题从未在IOS是支持,目前基本已经不再使用,现在使用的主要是MRC和APC。
Manual Referecen Counting(MRC)即手动引用计数,你需要手工维护所有的retain,release计数,你必须确保他们一一对应。
Automatic Reference Counting,自动引用计数,当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease。只需要像往常那样编写代码,只不过不写retain,release和autorelease三个关键字就行。
strong和weak的区别
strong和weak是APC中新加入的两个属性,
strong你可以简单理解为拥有对象的所有权。只要该指针指向某个对象,那么这个对象就不会被销毁。反过来说,ARC的一个基本规则即是,只要某个对象被任一strong指针指向,那么它将不会被销毁。如果对象没有被任何strong指针指向,那么就将被销毁。
在默认情况下,所有的实例变量和局部变量都是strong类型的。可以说strong类型的指针在行为上和MRC时代retain的property是比较相似的。
weak使用权指针。weak类型的指针指向对象,但是并不会持有该对象。
weak另一特点是归零,在一个对象销毁时在ARC机制作用下,所有指向这个对象的weak指针将被置为nil。释放不当造成的空指针是经常会碰到的问题,是c/c++使用多重指针的一种重要原因。使用ARC以后,不论是strong还是weak类型的指针,都不再会指向一个dealloced的对象,从根源上解决了意外释放导致的crash。
AutoreleasePool要点
1. AutoreleasePool核心是一个队列,每当你调用[blah autorelease]是时候,系统会在AutoreleasePool中注册一下,当你调用[poolrelease]的时候,系统会负责给队列中的每一项派发一个release。
2. [autorelease]是可以重复调用的,但你需要添加相应的retain来平衡。
3.还有一个新加入的方法[pool drain],APC下与release相同,GC下这个方法触发强制回收,而[pool release]是no-op。
4.老式的autoreleasepool看起来像这样子,
NSAutoreleasePool*pool = [[NSAutoreleasePool alloc] init;
// Codebenefitting from a local autorelease pool.
[poolrelease];
新式的写法如下,这种方式更快,根据苹果官方的说法autoreleasepool是NSAutoreleasePool的一个实例,本质上应该没有什么变化,但更效率。
@autoreleasepool
{
}
5. 一般来说main程序中有一个autoreleasepool,每个线程都需要有一个autoreleasepool。
同时,UI上每次事件处理时候开始的时候,ios会为我们自动生成一个autorelesepool,事件结束的时候释放掉。所以在事件处理中分配的对象在事件结束后就会释放掉,释放时间不确定。
6.在一些需要实时释放的地方可以加一个@autoreleasepool,当autoreleasepool中有大量的变量的时候是否回比较慢,最好拆分多个@autoreleasepool。
Retain Cycle
循环引用,典型的情况如下,
假设有三个对象,一个父类的父类,一个父类和一个子类。父类的父类持有父类的引用(retain),父类持有子类的引用(retain),子类持有父类的引用(retain)。父类的父类释放(release)父类,父类的父类被释放,而这时候父类和子类永远保持1的引用,游离在外。
解决Retain Cycle的办法就是ARC中使用__weak或__unsafe_unretained弱引用。