1、对于面向对象的语言,程序需要不断地创建对象。这些对象都是保存在堆内存中,而我们的指针变量中保存的是这些对象在堆内存中的地址,当该对象使用结束之后,指针变量指向其他对象或者指向nil时,这个对象将称为无用对象,因为没有指针指向它了,这种情况称为内存泄漏。当内存泄漏非常严重时,会导致内存不够用,程序就会崩掉。因此,内存管理是学习面向对象语言中非常重要也是非常头疼的一个问题。在Java、C++、OC等语言中都涉及到这些问题,Java的内存管理是非常轻松的,因为这些内存管理的工作都由虚拟机自动去完成,不需要程序员自己管理,C++就苦逼了,需要程序员时时刻刻注意内存管理,防止内存泄漏。而对于我们学习的OC语言,内存管理已经从最开始需要我们进行手动管理发展倒现在可以自动管理了,尽管现在已经不需要我们过多地关心内存管理问题,但是还是有必要了解一些基本概念和思想,这也是本篇文章的出发点。
2、内存管理其实主要就是两个方面的内容:内存分配和内存回收。
3、在Xcode4.2之前,OC的内存回收需要程序员花费大量的精力去理解内存回收相关的理论知识,并且程序中必须通过retain、release、autorelease等方法去管理对象的引用计数,这样才能让程序正常回收内存。Xcode4.2引入了新特性:自动引用计数(Automatic Reference Counting,ARC),ARC机制将会自动释放对象所占用的内存,通过启用ARC特性,我们不再需要重点关注内存回收相关的内容。
4、程序创建一个对象之后,怎么知道该对象什么时候应该被回收呢?OC中采用的是引用计数的机制来跟踪对象的状态:每个对象都有一个与之关联的整数,这个证书被称之为引用计数。在正常情况下,当一段代码需要使用某个对象时,应将该对象的引用计数加1,当这段代码不再需要该对象时,应该将该对象的引用计数减1,表示这段代码不再访问该对象了。当对象的引用计数为0时,表明没有任何程序需要该对象了,系统就会回收该对象所占用的内存。系统在销毁该对象之前,会自动调用该对象的dealloc方法(该方法继承自NSObject)来执行一些回收操作。如果该对象还持有其他对象的引用,此时必须重写dealloc方法,在该方法中释放该对象所持有的其他对象(通常就是将所持有对象的引用计数减1)。
5、在手动引用计数中,改变对象引用计数的方式如下:
NSObject中提供了有关引用计数的如下方法:
5、手动引用计数的基本思路就是谁(包括对象、函数等)把对象的引用计数加1,谁就要负责在“临死”前把该对象的引用计数减1,也就是说任何实体(包括对象、函数)在结束签都应该把其他对象的引用计数回复到开始前的状态。从这个角度来看,如果一个函数方法中返回一个对象,那么这个对象在方法结束后由于计数减1为0会被销毁,无法有效地将有效的指针对象返回给调用者,但是如果不按照上面的思路则又破坏了手动引用计数的基本原则。因此,我们需要一种有效而又优雅的解决方案——自动释放池。
所谓自动释放池(OC中有一个专门管理的类NSAutoreleasePool),就说一个存放对象的容器(比喻集合),自动释放池会保证延迟释放该池中所有的对象。所谓的自动释放,其实只是依次调用池中的每一个对象的release方法,将池中所有对象的引用计数减1.那么什么时候会自动释放呢?其实自动释放池(NSAutoreleasePool)的本质是采用MSMutableArray集合作为容器,当把对象添加到池中时实际上是把这些对象添加到MSMutableArray集合中,然后程序重写了MSMutableArray的release方法,并在该方法中依次调用容器中的每个对象的release方法。所以,当自动释放池(NSAutoreleasePool对象)调用release方法时我们加入自动释放池中的对象也就进行了释放。
如何将一个对象加入自动释放池呢?在前面第四点的时候降到了NSObject方法中有一个autorelease方法,任何对象调用该方法就可以将该对象加入到自动释放池中。
6、临时对象:对于Foundation中的类而言,当调用方法创建对象时,只要不是以alloc、new、copy、mutableCopy开头的方法创建出来的对象,系统就会默认创建自动释放的对象,这些对象称之为临时对象。
7、手动内存管理的规则总结如下:
8、在IOS 5 引入ARC之后,OC编程就不再需要过多地关注内存管理这一块的内容了。对于IOS开发者而言,最新的Xcode在创建IOS项目时已经默认已经开启ARC机制了,当然,你也可以通过项目属性选择关闭或开启ARC。"Building Setting"---> “Language Objective C” ---> "Objective - C Automatic Reference Counting"
9、现在最新的Xcode在代码中基本上会自动定义@autoreleasepool块,这其实就是自动释放池的上下文,任何在该上下文中创建的对象都由喜用的ARC来自动进行管理释放,并在释放结束后消除这些对象。合理使用@autoreleasepool相当于创建了一层自动释放区域:所有在@autoreleasepool范围内创建的变量,都会在@autoreleasepool结束时执行一次release,这样就可以保证这些对象在@autoreleasepool释放时获得提前释放的机会,从而降低了内存的占用率。
10、在正常情况下,如果某个函数很长,且在该函数运行过程过程中出现很多中间变量,占据了大量的内存,或者程序在执行过程中创建了大量的临时对象(比喻在循环中创建对象),程序可能需要多次释放这些临时对象,这次程序可以考虑将@autoreleasepool块放在循环体内。
1 for(int i = 0 ; i < 100 ; i++)
2 {
3 @@autoreleasepool{
4 //创建临时对象
5 //调用临时对象的方法
6 。。。
7 }
8 }