开发IOS也有一些时间了,到目前写这篇文章为止我还是很OUTt的没有用过ARC。这两天由于最后项目收工需要检测内存泄露,积累了一些内存管理知识,记录一下。
其实Obj-C的内存机制已经属于常识,简单概括就是:
1. 开辟内存地址空间,是通过诸如alloc, new, copy等方法分配出去,这样才能被程序中的指针变量引用到;
2. 回收内存地址空间的原则是,当一块内存空间不再被任何指针变量引用时,即没有任何指针变量指向这个空间时释放;
这两条是指导性原则,具体在Obj-C中,一块内存地址是否处于被引用状态完全依赖于其retainCount的值。只有当retainCount等于0的时候,该内存才会触发释放条件。基本上来说:
1.生成对象(retainCount 0->1):alloc, copy, new;
2.保留对象(retain x->x+1):[self retain];
3.释放对象(release x->x-1):[self release];
retainCount是唯一是否释放该内存的标准,我觉得这句话其实甚至比原理“没有任何指针变量指向这个空间时释放”这个陈述更正确,或者说两者并不一致。如下例:
NSObject * a = [[NSObject alloc]init];
a = nil;
过程如图所示,结果就是这个地址空间并没有被释放,尽管已经没有任何指针指向该地址,这就发生了内存泄露(Memory Leak),内存泄露的定义是:A memory leak is a piece of allocated memory that nothing points to. 换言之,在内存管理中,仅仅没有指针指向该地址是不够的,而是要在每一个指针在不指向该地址时释放对该地址的所有权,即retainCount = 0才行。上例中如果加入以下语句:
NSObject * a = [[NSObject alloc]init];
NSLog(@"%d", a.retainCount);
a = nil;
这时输出1,说明地址空间的retainCount为1,而a指针没有释放该retainCount就指向了其他的地址,导致内存泄露。
这种情况在对类对象进行赋值的时候屡见不鲜,如Class A有成员变量a,:
-(id)init {
if(self = [super init]) {
a = [NSDate new]; //retainCount = 1
}
return self;
}
如果这是在某个函数中,将a赋给了别的值,或者清空,都将导致内存泄露。解决的方法通常有两种:
1. self.a = [NSDate date];
2. NSDate * dt = [NSDate new];
self.a = dt;
[dt release];
这两种代表的含义不同,[NSDate date]是一个+方法,即为类方法,其实会自动地对该对象进行autorelease.类似的方法有很多,如[NSString stringWithFormat],[UIColor redColor]等,都是很常用的方法,要积极地使用。
以上两种方法有一个问题,就是实际上,dt这块空间的归属权已经过渡给a,通过self.a这个函数。这里要说说self.a, self.a相当于[self setA:(NSDate *)dt],这个方法可以重载,其执行过程类似于:
-(void)setA:(NSDate *)dt {
[dt retain];
[a release];
a = dt;
}
有些情况下,变量的归属权未知,比如函数调用时,这个时候需要使用autorelease,如:
-(void)foo {
return [[NSDate new] autorelease];
}
基本的使用原理就是这样,其实不难掌握。但在实际过程中,有很多时候理解了原理并不足以应对一些情况。例如有时候变量可能在被系统函数调用,retaincount不等于0甚至等于3或者4,这个时候要判断是否已经将代码中引用到的部分释放掉。有些情况比较特殊,会导致类不执行dealloc从而引起内存泄露。如:
1.Animation。记得[self.view.layer removeAllAnimations];
2.Delegate。在viewDidDisappear时,将所有以本类为delegate对象的变量设为nil;
3.NSTimer。一定要将NSTimer进行Invalidate,并清除为nil;
有一些工具能辅助内存管理,在XCode中拉开左上角Run圆圈的小箭头,选择Analyze,生成代码间的内存分析条目:
点击蓝色的按钮,还会有高端的线条效果告诉你泄露的位置和可能性。
第二个工具就是大家熟知的Instruments,在XCode中选择Profile,或者如果有真机的话可以直接在Instruments的MemoryLeak里把Target选择你的Device。
有一点,如何理解Instruments的几个参数:
这两张表格里很清晰,最重要的参数就是Live Bytes,或者#Living,基本一回事,代表目前App正在占用的内存,Transitory指的是已经释放掉的内存,而Overall指的是包括已经释放和还未释放的总内存。
如果想从Instruments中得到Leak的代码,选择View->Extended Detail即可。
基本就是以上,为了兼顾所有的点我没有说得太深,以后有时间补上吧。
相关知识
深入理解移动应用开发:从概念到实践
【视频花屏问题】解码天书:深入理解视频流花屏现象及其解决方案
深入理解BootStrap
深入理解深度学习——正则化(Regularization):噪声鲁棒性
宝剑九正位详解:深入解读其意义
康乃馨花语与寓意(康乃馨花语深入解析)
剑兰花(剑兰花的花语及寓意深入解读)
4个科学理论帮你理解桃花的魅力
谈谈对《春江花月夜》哀而不伤情感基调的理解
芍药的花语——华丽与坚韧的化身(深入解读芍药花语)
网址: 深入理解Objective https://m.huajiangbk.com/newsview1293871.html
上一篇: 吊兰不长小吊兰怎么办,吊兰为什么 |
下一篇: ios开发网络请求Domain= |