自动引用计数:自动管理引用计数
使用ARC,引用计数还是要执行,ARC自动添加保留与释放操作。
ARC会自动执行retain、release、autorelease等操作,所以在ARC下直接调用下面方法是非法的:
- retain
- release
- autorelease
- dealloc
ARC调用这些方法,不通过普通的消息派发机制,而是直接调动其底层C语言版本,节省很多CPU周期。
使用ARC时必须遵循的方法命名规则
ARC将内存管理语义在方法名中表示出来确立为硬性规定。
若方法名以下列词语开头,则其返回的对象归调用者所有:
- alloc
- new
- copy
- mutableCopy
调用上述四种方法的那段代码要负责释放方法所返回的对象。
若方法名不以上述四个词语开头,则表示其所返回的对象不归调用者所有。返回的对象会调用autorelease添加到自动释放池中自动释放,返回对象在跨越方法调用边界后依然有效。
ARC除自动调用保留与释放操作外,还有可以执行一些手工操作很难甚至无法完成的优化。
// ARC优化举例:
_myPerson = [EOCPerson personWithName:@"Bob Smith"];
调用personWithName方法返回对象,根据方法命名规则可以得出对象在返回之前调用了autorelease方法,由于实例变量是强引用,所以编译器在设置其值的时候还要执行一次保留操作。
与下面代码等效:
EOCPerson *tmp = [EOCPerson personWithName:@"Bob Smith"];
_myPerson = [tmp retain];
可以看出personWithName方法中调用的autorelease方法和上面代码中的retain都是多余的。
ARC为优化代码在运行期会检测多余操作。在方法中返回自动释放的对象时,不再直接调用对象的autorelease方法,而是改为调用objc_autoreleaseReturnValue,设置全局数据结构中的一个标志位,此函数会检视当前方法返回之后即将要执行的那段代码,是否要保留回返对象上,若要保留对象,那么不执行autorelease,若不保留对象,那么需要再执行autorelease。
若返回一个自动释放的对象,调用代码要保留对象,那么此时不再直接执行retain,改为执行objc_retainAutoreleaseReturnValue函数,此函数要检测之前设置的标志位,若已经置位,则不执行retain操作,执行清理标志位操作。
设置并检测标志位,要比调用autorelease和retain更快。
变量的内存管理语义
ARC也会处理局部变量和实例变量的内存管理。默认情况下,每个变量都是指向对象的强引用。
ARC会用一种安全的方式来设置:先保留新值,再释放旧值,最后设置实例变量。
可用下列修饰符来改变局部变量与实例变量的语义:
- __strong:默认语义,保留此值。
- __unsafe_unretained:不保留此值,这么做可能不安全,因为等到再次使用变量时,其对象可能已经回收了。
- __weak:不保留此值,但是变量可以安全使用,因为如果系统把这个对象回收了,那么变量也会自动清空。
- __autoreleasing:把对象“按引用传递”给方法时,使用这个特殊的修饰符。此值在方法返回时自动释放。
ARC如何清理实例变量
// MRC下:
- (void)dealloc
{
[_foo release];
[_bar release];
[super dealloc];
}
ARC也负责对实例变量进行内存管理,在“回收分配给对象的内存”时生成必要的清理代码。
ARC之后一般不需再编写dealloc方法,ARC会借用Objective-C++的一项特性来生成清理例程:编译器如果发现某个对象里含有C++对象,就会生成名为.cxx_destruct析构的方法,方法中有自动调用超类dealloc的方法。回收Objective-C++对象时,待回收的对象会调用所有C++对象的析构方法,利用该方法中生成清理内存所需的代码。
非Objective-C的对象,如CoreFoundation中的对象或是由malloc()分配在堆中的内存,仍需要清理
// ARC下:
- (void)dealloc
{
CFRelease(_coreFoundationObject);
free(_heapAllocatedMemoryBlob)
}
覆写内存管理方法
MRC下,可以覆写内存管理方法。
ARC下,不能这么做,这样会干扰分析对象的生命周期的工作。
网友评论