苹果的官方说明中称,ARC是“由编译器进行内存管理”的,可是实际上只有编译其是没法彻底胜任的,再次基础上还须要Objective-C运行时库的协助。 也就是说,ARC由如下工具、库来实现。bash
{
id __strong obj = [[NSObject alloc] init];
}
复制代码
~~本人是c/cpp小白,没有编译成功,没看到汇编输出TAT~~编辑器
以上代码编译器的模拟代码:函数
/** 编译器的模拟代码 */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);
复制代码
如上所示,调用了2次objc_msgSend
方法,变量的做用域结束时经过objc_release
释放对象。虽然ARC有效时不能使用release方法,但由此可知编译器自动插入了release
。工具
使用alloc/new/copy/mutableCopy之外的方法时:优化
{
id __strong obj = [NSMutableArray array];
}
复制代码
编译器的模拟代码以下:ui
/** 编译器的模拟代码 */
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
复制代码
其中的objc_retainAutoreleasedReturnValue
函数主要用于优化程序运行,它用于本身持有(retain)对象的函数,但它持有的对象应为返回注册在autoreleasepool中对象的方法,或是函数的返回值。在调用alloc/new/copy/mutableCopy之外的方法,由编译器插入该函数。spa
与 objc_retainAutoreleaseReturnValue
函数相对的函数为objc_autoreleaseReturnValue
函数。它用于alloc/new/copy/mutableCopy方法之外的NSMutableArray类的array类方法等返回对象的实现上。code
+ (id) array
{
return [[NSArray alloc] init];
}
复制代码
转换后对象
+ (id) array
{
id obj = objc_msgSend(NSArray,@selector(alloc));
objc_msgSend(obj,@selector(init));
return objc_autoreleaseReturnValue(obj);
}
复制代码
返回注册到autoreleasepool中对象的方法使用了objc_autoreleaseReturValue
函数返回注册到autoreleasepool中的对象。可是objc_autoreleaseReturValue
函数同objc_autorelease
函数不一样,通常不只限于注册对象到autoreleasepool中。内存
objc_autoreleaseReturValue
函数会检查使用该函数的方法或函数调用方的执行命令列表。若是方法或函数的调用方在调用了方法或函数后紧接着调用objc_retainAutoreleasedReturnValue()
函数,那么就不将返回的对象注册到autoreleasepool中,而直接传递到方法或函数的调用方。objc_retainAutoreleasedReturnValue
函数与objc_retain
函数不一样,它即使不注册到autoreleasepool中而返回对象,也可以正确地获取对象。
经过objc_autoreleaseReturnValue
函数和objc_retainAutoreleasedReturnValue
函数的协做,能够不讲对象注册到autoreleasepool中而直接传递,这一过程达到了最优化。
{
id __weak obj1 = obj;
}
复制代码
/** 编译器的模拟代码 */
id obj1;
objc_initWeak(&obj1,obj);
objc_destroyWeak(&obj1);
复制代码
经过objc_initWeak
函数初始化附有__weak
修饰符的变量,在变量做用域结束时经过objc_destroyWeak
函数释放该变量。
如如下源码所示,objc_initWeak
函数将附有__weak
修饰符的变量初始化为0后,会将赋值的对象做为参数调用objc_storeWeak函数。
obj1 = 0;
objc_storeWeak(&obj1,obj);
复制代码
objc_destroyWeak
函数将0做为参数调用objc_storeWeak函数。
objc_storeWeak(&obj1,0);
复制代码
即前面的源代码和如下代码相同:
id obj1;
obj1 = 0;
objc_storeWeak(&obj1,obj);
objc_storeWeak(&obj1,0);
复制代码
objc_weakStore函数把第二参数的复制对象的地址做为键值,将第一参数的附有__weak修饰符的变量的地址注册到weak表中,若是第二参数为0,则把变量的地址从weak表中删除。
weak表与引用计数表相同,做为散列表被实现。若是使用weak表,将废弃对象的地址做为键值进行检索,能高速地获取对应的附有__weak修饰符的变量的地址。另外,因为一个对象能够同时赋值给多个附有__weak修饰符的变量中,因此对于一个键值,可注册多个变量的地址。
释放对象时,废弃谁都不持有的对象,经过objc_release函数释放。
_objc_rootDealloc
对象被废弃时最后调用的objc_clear_deallocating函数动做以下:
根据以上步骤,前面说的若是附有__weak修饰符的变量所引用的对象被废弃,则将nil赋值给该变量这一功能即被实现。由此可知,若是大量使用附有__weak修饰符的变量,则会消耗相应的CPU资源,对此只在须要避免循环引用的时候使用__weak修饰符。
使用__weak修饰符时,如下代码会引发编译器警告
{
id __weak obj = [[NSObject alloc] init];
NSLog(@"obj = %@",obj);
}
复制代码
编译结果以下:
Assigning retained object to weak variable; object will be released after assignment
复制代码
编译器模拟代码以下:
id obj;
id temp = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(temp,@selector(init));
objc_initWeak(&obj,temp);
objc_release(temp);
objc_destroyWeak(&obj);
复制代码
运行结果以下:
2017-12-07 19:37:24.075939+0800 ImageOrientation[10963:3581164] obj = (null)
复制代码
使用附有__weak修饰符的变量,便是使用注册到autoreleasepool中的对象。
{
id __weak obj1 = obj;
NSLog(@"%@",obj1);
}
复制代码
该代码能够转换为以下形式:
/** 编译器模拟代码*/
id obj1;
objc_initWeak(&obj1,obj);
id temp = objc_loadWeakRetained(&obj1);
objc_autorelease(temp);
NSLog(@"%@",obj1);
objc_destroyWeak(&obj1);
复制代码
与赋值时相比,在使用附有__weak
修饰符变量的情形下,增长了对objc_loadWeakRetained
函数和objc_autorelease
函数的调用。这些函数的动做以下:
objc_loadWeakRetained
函数取出附有__weak修饰符变量所引用的对象并retainobjc_autorelease
函数将对象注册到autoreleasepool中。将对象赋值给附有__autoreleasing修饰符的变量等同于MRC时调用对象的autorelease方法。
@autoreleasepool{
id __autoreleasing obj = [[NSObject alloc] init];
}
复制代码
模拟代码以下:
/** 编译器的模拟代码 */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_autoreleas(obj);
objc_autoreleasePoolPop(pool);
复制代码
alloc/new/copy/mutableCopy以外的方法实现:
@autoreleasepool{
id __autoreleasing obj = [NSMutableArray array];
}
复制代码
/** 编译器的模拟代码 */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutorelesedReturnedValue(obj);
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);
复制代码
获取引用计数的函数为CFGetRetainCount
例如:
{
id __strong obj = [[NSObject alloc] init];
NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
结果为1
复制代码
{
id __strong obj = [[NSObject alloc] init];
id __weak obj1 = obj;
NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
结果为2
复制代码
{
id __strong obj = [[NSObject alloc] init];
id __autoreleaing obj1 = obj;
NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
结果为2
复制代码
{
id __strong obj = [[NSObject alloc] init];
@autoreleasepool{
id __autoreleaing obj1 = obj;
NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
}
NSLog(@"retainCount = %ld",CFGetRetainCount((__bridge CFTypeRef)obj));
}
结果为2和1
复制代码