IOS内存管理解

        开发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即可。

基本就是以上,为了兼顾所有的点我没有说得太深,以后有时间补上吧。


            

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值