内存管理
内存管理原则
自己生成的对象自己持有
alloc、new、copy、mutable以及符合以这些关键字为前缀并且符合驼峰拼写法命名的都是自己生成并持有的非自己生成的对象自己也能持有
除alloc、new、copy、mutableCopy等去得的对象都为非自己生成但自己持有,我们也有义务对其进行释放如果在MRC中不再需要自己持有的对象时释放
自己持有的对象需要释放,但如果仅仅是对象存在但不持有,则不需要自己释放对象,例如取得注册到Autorelease表中的对象则不需要我们释放非自己持有的对象无法释放
如果过度释放会因为释放了非自己持有的对象而引起崩溃,如果释放取得的对象存在但自己不持有,也会崩溃。
内存管理实现
alloc\retain\release\delloc
猜测苹果的引用计数是通过散列表来管理引用计数的,主要通过CFDoExternRefOperation来进行分发操作的,大概步骤是先通过函数找到散列表Table,然后根据retainCount/retain/release等进行分发操作来记录引用计数autorelease
其实跟C语言中得局部变量类似,超出作用域则自动废弃。其生命周期可以看做:生成并持有NSAutoreleasePool对象-调用已分配对象的autorelease方法-废弃NSautoreleasePool(这里被分配的对象也会自动调用release进行释放),NSRunLoop每次循环时都会将废弃的NSAutoreleasePool进行处理,大量读取图像并进行操作的时候最好每个都放在AutoreleasePool中进行不然会产生大量autorelease,造成内存不足。其实现可看做 :push到Pool中--autorelease 将对象加到autoreleasepool池中--pop 相对于废弃NSAutoreleasePool对象
ARC规则
所有权修饰符
strong 修饰符
oc中的对象默认修饰符都是strong类型,通过strong修饰无需再retain或者releaseweak修饰符
weak的出现是为了解决循环引用而引起的内存泄露,他是弱引用不持有对象,而且他会自动置为nil,unsafe_unretained修饰符
是不安全的修饰符,他不属于编译器的内存管理对象,因此使用它得非常小心,容易造成垂悬指针,所以使用它时一定要保证他的对象存在autorelease修饰符
被autorelease修饰的对象会被注册到autoreasePool池中,保证其对象存在 但不被持有,一般除了alloc/new/copy/mutableCopy以及符合驼峰命名法生成的对象都是注册到autorelease中,而且weak修饰的对象也会被注册到autorelease中,而且id的指针都是默认被autorelease修饰,
规则
- 不能使用retain/release/autorealse/dealloc/retainCount/autorelease
- 不能使用NSAllocateObject和NSDeallocateObject
- 须遵循内存管理的命名法则
- 使用@autorelease{}代替NSAutoreleasePool
- 不能使用区域NSZone
- 对象变量不能作为C语言的结构体的的成员 需加unsafe_unretained修饰符
- 显示转换”id“ 和”void *“ 通过bridge(bridge_retained和bridge_transfer) 可以进行互换
ARC实现
- strong修饰符
在运行时自动给我上了release
NSObject *obj = [[NSObject alloc] init];
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msgSend(obj,@selector(init));
objc_release(obj);
NSAarray *arr = [NSArray array];
+(id)array{
return [[NSArray alloc] init];
}
id obj = objc_msgSend(NSArray,@selector(init));
objc_retainAutoreleaseReturnValue(obj);
objc_release(obj);
id obj = objc_msgSend(NSArray,@selector(alloc));
objc_msgSend(obj,@selector(init));
return objc_autoreleaseReturnValue(obj);
objc_autoreleaseReturnValue 和 objc_retainautoreleasedReturnValue成对出现,不需要注册到autoreleasepool中,而直接进行传递保证对象的存在,这一过程达到了最优化
- weak修饰符
{
id obj1 = obj;
}
id obj1;
objc_initWeak(&obj1,obj);
objc_destoryWeak(&obj1,0);
通过objc_initWeak函数初始化weak 修饰的变量,在变量作用域结束时调用objc_destoryWeak函数释放该变量。其中objc_storeWeak(&obj1,obj)处理,如果obj超出了作用域objc_storeWeak(&obj1,0),然后把变量的地址从weak表中移除,NSMachPort不支持weak
- autorelease修饰符
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject,@selector(alloc));
objc_msdSend(obj,@selector(init));
objc_autorelease(obj);
objc_autoreleasePoolPop(pool);