Love.Passion.Dream

iOS内存管理与内存泄露

iOS上开发应用对于内存泄露一定要引起重视,因为iOS上应用程序一旦启动了可能部分用户不会去主动关闭它们,点击home键之后回到主屏幕但是程序依然在后台运行,那么一旦有一丝内存泄露,那么最终带来的将会是应用程序使用的内存不断的增加,最终导致程序的崩溃。

在Mac上开发iOS的应用是一件让人很愉悦的事情,因为苹果帮你考虑到了一切,这也是苹果封闭的系统带来的福利,我们不用考虑用什么工具,因为一切都已经为你安排好了,你需要做的就是学会使用它帮助你找到内存泄露的地方。

大家想必都是在mac上面用xcode启动一个模拟器来进行基础的开发,xcode有一套非常完善的性能优化工具:

里面的Leaks就是用来排查内存泄露的。

1:如何启动leaaks工具排查内存泄露

点击菜单栏的Product -> Profile然后如果没有编译错误的话就会弹出上图那个界面,然后选择Leaks后就能够打开如下的工具了:

图中红色的部分就是出现内存泄露的地方,然后在下面可以通过不同的方式去查看具体的信息,还能定位的代码中具体的位置,用来分析导致内存泄露的地方。

2:工具中的数据都意味着什么

上图可以看到非常多的信息,但是各项都代表什么意思?我们能够从中获取到什么呢?

上面这张图可以看到除了最下面那个控制台选项,我们一共有三种方式查看引发内存泄露的信息。

第一个选项选择后会列出没有回收的对象已经显示具体的信息,包括该对象导致泄露的空间大小。

第二个选项可以看到泄露的内存直接的关系,可以通过这个直观的看到时候有循环引用。

第三个选项则通过树状的结构展示了泄露内存分配的一个情况,可以通过这个直接查到被泄露内存在代码中被分配的位置,当然如果你是引用的一个第三方的二进制的库,那么很遗憾你将看不到具体的代码情况。

3:引起各种内存泄露的原因

结合工具提供的信息可以很轻松的定位到引发内存泄露的原因,所有的原因中归根到底就是内存没有被释放掉。最常出现的有两种情况,一是局部使用的变量没有被释放掉,这个在alloc的时候使用autorelease就可以了,如果不是自动内存管理的则需要手动release掉,但是每次release只会使得retainCount-1,只有retainCount为0的时候才会释放掉。通常无法release可能是由于循环引用导致的

避免retain cycle,即:有A,B两个Object, A中有一个B的实例变量,B中又有一个A的实例变量,要release A就必须releaseA中的B,而要release B有必须release B中的A,这样就产生了一个Retain Circle,A B都不能被dealloc.解决Retain Circle的方法就是使用弱引用(weak reference),弱引用没有被引用的那个Object的所有权,也就不需要release它,从而解决了Retain Circle问题.为了防止Retain Circle的发生, delegate通常都是弱引用的, 因此我们一般不应该retain一个delegate。NSURLConnection是个例外

第二种情况是当对象被释放的时候没有在dealloc函数中释放掉由该对象所拥有的对象,也就是必须明确对对象的所有权,如果A对象中创建了B对象,那么她要负责在自己呗释放的时候也释放掉它所拥有的对象。

4:object-c的内存管理

object-c 的内存管理有三种方式,一种是传统的手动的保留计数发,这种方法就是通过对象中的retainCount来管理,通过retain和release来手动的处理对象的释放。虽然这种方式比较麻烦,但是它也跟容易完全控制,性能也最优。

另外一种就是内存自动释放,在某一段程序前新建一个内存池,然后该段程序结束后释放内存池会将该内存池中autorealse的内存都释放掉。但是苹果公司建议iPhone的开发最好不要选择这种方式。但是一般cocoa的规范里面,你如果是通过一个函数拿到一个对象,那么这个函数里面应该是对该对象做了autorelease的处理,所以如果你编写的对象的函数返回一个对象的话,那么你需要负责给它发送一条autorelease消息。

autorelease 是一次循环运行时 如果在一次runloop到了就会最做一次处理 如果没有其它地方强引用了 就释放了

最后在Object-C 2.0 中引入了垃圾自动回收的概念,你可以开启垃圾回收(GC)来启用,当某个对象的引用为0之后便会自动释放掉该对象。该方法通过设置 xxx = nil 的方式可以来释放内存,这种方式在很多高级语言,例如JAVA。

5:开发iOS应用需要注意处理内存的要点

iOS不同于MAC OS 尤其是在iPhone中,所以有一些要点需要注意,这样有益于提高应用程序的效率。

a.记得释放你的内存,否则用户不关闭程序要么最终你的程序将会崩溃

b.需要的时候可以使用autorelease,但是你的程序尽量还是使用手动的方式管理你的内存。

c.如果不是通过alloc 和 new copy 得到一个对象,那么可以假定该对象已经是被设置了autorelease,除非你要对其做特殊保留,否则你不需要对其有任何操作。

d.参照上一条如果你保留了某个对象,记得保证你的retain和release中相同。

e.注意特性(propety)中对内存的处理,如果使用了retain的特性扩展,那么记得在delloc的适合释放保留的对象。

(未完待续.....)第一次写iOS的文章,新手新手,欢迎拍砖!~