这是个人第一篇文章,有什么不对的地方还烦请你们指出啦,总以为作开发颇有必要作笔记,方便记录本身的所得也能与你们探讨,可是以前一直比较懒因此无所做为,那接下来的时间一块儿好好努力吧各位加油加油。编程
了解内存管理的最普通的方式是考虑全部权。若是Manny对Jack曾说过alloc,retain或者copy,则表示Manny已经宣称对Jack的全部权。多个对象能够同时拥有Jack,但每一个对象只负责正确地管理本身对Jack的全部权,最终释放Jack是每一个Jack全部者的责任,而Jack的非全部者永远不须要释放Jack。只要全部拥有Jack全部权的对象都以这种方式执行,Jack就不会泄漏也不会有任何指向Jack的指针留下来摇晃。安全
野指针:指针变量没有进行初始化或指向的空间已经释放。多线程
内存泄漏:框架
在ARC自动引用计数模式下,形成内存泄漏的状况:函数
在MRC手动引用计数模式下,形成内存泄漏的状况:优化
僵尸对象:堆中已经被释放的对象(retainCount=0)。atom
空指针:指针赋值为空(nil)。spa
一个变量的名称,包括实例变量,只是一个指针。当你向该指针发送消息时,你实际上就是经过该指针将消息发送到它指向的对象。内存管理的规则是关于对象的原则,而不是关于名称、引用或指针的规则。你不能递增或递减一个指针的保留计数,由于没有这个东西。指针所占用的内存是自动管理的(并且很小)。内存管理所关注的是指针所指向的对象。.net
Objective-C对象中保存着引用计数这一整数值。调用alloc或者retain方法后,引用计数+1。调用release后,引用计数-1。引用计数为0时,调用dealloc方法废弃对象。线程
对象操做 | Objective-C方法 | 引用计数 |
---|---|---|
生成并持有对象 | alloc/new/copy/mutablecopy | 1 |
持有对象 | retain | +1 |
释放对象 | release | -1 |
废弃对象 | dealloc | 0 |
本身生成的对象,本身持有
NSObject *obj = [[NSObject alloc] init];
[obj retain];
NSLog(@"obj - %lu",[obj retainCount]);
复制代码
非本身生成的对象,本身也能持有
id obj = [NSMutableArray array];
[obj retain];
NSLog(@"obj - %lu",[obj retainCount]);
复制代码
再也不须要本身持有的对象时释放
NSObject *obj = [[NSObject alloc] init];//本身生成本身持有
[obj retain];
NSObject *obj2 = [obj retain];//非本身生成,本身持有
[obj release];
[obj2 release];
NSLog(@"obj - %lu",[obj retainCount]);
复制代码
非本身持有的对象本身没法释放
id obj = [NSMutableArray array];
[obj release];
复制代码
MRC下对象的引用计数能够经过[object retainCount]方法得到。
autorelease故名思议就是自动释放,看上去很像ARC,但其实更相似于C语言中的局部变量,也就是说,超出变量做用域的时候将自动被废弃,但这里与C语言不一样的是,编程人员能够手动设置其做用域。 autorelease的具体使用方法以下:
NSAutoreleasePool对象的生命周期至关于C语言变量的做用域,对于全部调用过autorelease方法的对象,在废弃NSAutoreleasePool对象时,都将对对象统一调用release方法,代码以下所示:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init] ;
id obj = [ [NSObject alloc]init];
[obj autorelease] ;
[pool drain];
复制代码
在Cocoa框架中,若是不是使用alloc/new/copy/mutablecopy这几个方法返回的对象,其他方法返回的对象都将自动注册到NSAutoreleasePool中,id array = [NSMutableArray arrayWithCapacity:10];其实也就等同于:id array = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
ARC是Objective-C编译器的特性,而不是运行时特性或者垃圾回收机制,ARC所作的只不过是在代码编译时为你自动在什么时候的位置插入release或者autorelease,减小了开发的工做量。但咱们有时仍须要四种全部权修饰符来配合ARC来进行内存管理。
__strong:强引用,持有所指向对象的全部权,无修饰符状况下的默认值。如需强制释放,可置nil(这里先建立一个指针,将新的值retain一次,将指针动态指向新的值,并将旧的值release一次)。
NSObject *obj = [[NSObject alloc]init];
//他们是等价的
NSObject __strong *obj = [[NSObject alloc]init];
复制代码
__weak:弱引用,不持有所指向对象的全部权,引用指向的对象内存被回收以后,引用自己会置nil,避免野指针.避免循环引用,会将对象注册到autoreleasepool(既不保留新值,也不释放旧值,动态地将指针指向新的值,若是这个值刚被dealloc,就会将指针更新为一个nil指针)。
unsafe_unretained:至关于assign。直接赋值。引用计数不变。他会发生野指针现象。因此不安全。不像weak,当指向的对象为空的时候,将指针置为nil。
_autoreleasing:将对象赋值给附有 _ autoreleasing 修饰符的变量等同于ARC 无效时调用对象的autorelease方法。
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
复制代码
__strong底层实现
alloc/new/copy/mutablecopy状况下
//alloc为例的模拟底层代码为:
id __Strong obj = [[NSObject alloc] init];
id obj = objc_msgSend(NSobject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
//编译器自动帮咱们加入了release,来释放对象
复制代码
非alloc/new/copy/mutablecopy状况下
//array为例的模拟底层代码为:
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
//objc_retainAutoreleasedReturnValue(obj)是主要用于最优化程序运行
//array方法的底层模拟为:
id obj = objc_msgSend(NSmutableArray,@selector(alloc));
objc_msgSend(obj,@selector(init));
return objc_autorealeaseReturnValue(obj);
复制代码
objc_autorealeaseReturnValue(obj)与objc_retainAutoreleasedReturnValue(obj)是成对的,objc_autorealeaseReturnValue(obj)会把对象注册到autorealeasepool中,可是若是它检测到方法执行列表中出现objc_retainAutoreleasedReturnValue(obj)方法,那么就不会将返回的对象注册到autorealeasepool,而是直接传递到方法和函数的调用方。这样直接传递能够达到最优化。
__weak底层实现
__weak源码
id __weak obj1 = obj;
//模拟代码
id obj1;
obj1 = 0;
objc_storeWeak(&obj1,obj);
objc_destoryWeak(&obj1); 等同于objc_storeWeak(&obj1,0);
复制代码
objc_storeWeak(&obj1,obj)函数将第二个参数的赋值对象的地址做为键值,将第一个参数的附有__weak修饰符的变量的地址注册到weak表中,若是第二个参数为0,则把变量的地址从weak中删除。一个键值能够注册多个变量的地址因而可知,若是大量的weak变量,则会消耗CPU资源,因此weak 只用来避免循环引用。
__weak与@autoreleasepool
id __weak obj1 = obj;
NSLog(@"%@",obj1);
//模拟代码
id obj1;
objc_initWeak(&obj1,obj);
id temp = objc_loadWeakRetained(&obj1);
objc_autorelease(temp);
NSLog(@"%@",temp);
objc_destoryWeak(&obj1);
复制代码
因此在@autorealeasepool块结束前能够放心使用weak修饰变量
__autoreleasing底层实现
将对象赋值给附有__autoreleasing修饰符的变量等同于ARC无效时,调用对象的autorelease方法。
使用alloc/new/copy/mutableCopy时
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
//模拟代码
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_autorelease(obj);
objc_autoreleasPoolPop(pool);
复制代码
使用alloc/new/copy/mutableCopy之外的方法时
@autoreleasepool {
id __autoreleasing obj = [NSMutableArray array];
}
// 模拟代码
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray,@selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_autorelease(obj);
objc_autoreleasPoolPop(pool);
// 虽然 obj 持有对象的方法变为 objc_retainAutoreleasedReturnValue, 可是将 obj 所引用的对象注册到 autoreleasepool 中的方法并无改变
复制代码
关于@autoreleasepool,在ARC下应该使用@autoreleasepool而不是NSAutoreleasePool,@autoreleasepool的具体实现将在以后的文章中继续探讨。
ObjC2.0引入了@property,提供成员变量访问方法、权限、环境、内存管理类型的声明,下面主要说明ARC中属性的内存管理。属性的参数分为三类,基本数据类型默认为(atomic,readwrite,assign),对象类型默认为(atomic,readwrite,strong),其中第三个参数就是该属性的内存管理方式修饰,修饰词能够是如下之一:
assign
直接赋值,通常用来修饰基本数据类型。固然也能够修饰ObjC对象,可是不推荐,由于被assign修饰的对象释放后,指针仍是指向释放前的内存,在后续操做中可能会致使内存问题引起崩溃。
@property (nonatomic, assign) NSInteger count;
复制代码
retain
retain和strong同样,都用来修饰ObjC对象,使用set方法赋值时,实质上是会先保留新值,再释放旧值,再设置新值,避免新旧值同样时致使对象被释放的的问题。
//MRC写法以下
- (void)setCount:(NSObject *)count {
[count retain];
[_count release];
_count = count;
}
//ARC对应写法
- (void)setCount:(NSObject *)count {
_count = count;
}
复制代码
copy
通常用来修饰String、Dict、Array等须要保护其封装性的对象,尤为是在其内容可变的状况下,所以会拷贝(深拷贝)一分内容給属性使用,避免可能形成的对源内容进行改动。使用set方法赋值时,实质上是会先拷贝新值,再释放旧值,再设置新值。实际上,遵照NSCopying的对象均可以使用copy,固然,若是你肯定是要共用同一份可变内容,你也可使用strong或retain。
weak
ARC新引入修饰词,可代替assign,比assign多增长一个特性(置nil)。weak和strong同样用来修饰ObjC对象。使用set方法赋值时,实质上不保留新值,也不释放旧值,只设置新值。
@property (weak) id<MyDelegate> delegate;
复制代码
strong
ARC新引入修饰词,可代替retain,ARC通常都写strong。
Person *per = [[Person alloc] init];
self.person = per;
若是是strong,对象的retainCount为2,若是为weak,对象的retainCount为1。
unsafe_unretained
等价于assign,能够用来修饰数据类型和OC对象,可是不会使计数器加1,且对象销毁时也不会将对象指向nil,容易形成野指针错误。
OC中使用block必须本身管理内存,错误的内存管理将致使循环引用等内存泄漏问题,这里主要说明在ARC下block声明和使用的时候须要注意的两点:
若是你使用@property去声明一个block的时候,通常使用copy来进行修饰(固然也能够不写,编译器自动进行copy操做),尽可能不要使用retain。
@property (nonatomic, copy) void(^block)(NSData * data);
复制代码
block会对内部使用的对象进行强引用,所以在使用的时候应该肯定不会引发循环引用,固然保险的作法就是添加弱引用标记。
__weak typeof(self) weakSelf = self;
复制代码