备注:本来在一年前有一个出版社找到我,让我写一系列关于iOS性能优化的书。但是一直因为工作原因,没有能够按时交付。(其实就是自己懒)所以现在讲已经写好的部分章节分享到博客中,希望对大家有所帮助,如果有什么不对的地方,也希望大家指正出来,大家共同讨论。也可以加我qq:1583042987,备注写上博客园,大家一起讨论一下关于iOS的技术。好了,进入正文。
想要了解objective-c中的内存管理,首先需要知道引用计数的概念,那什么是引用计数?很多初学者对此的了解都局限于概念,并没有真的理解。那接下来用一个例子来解释这一个抽象的概念。
在学校的图书馆里,有一个班级组织阅读活动,图书馆此时对该班级开发,每一名学生都去图书馆借用一到多本书,此时学生持有的资源也就是书的数量,而图书馆对于班级的每个人员的借书情况都进行了纪录,当学生阅读结束后,需要将书的资源释放,归还给图书馆,当所有学生都将书归还的时候,即代表这次阅读活动结束,图书馆将关闭对该班级的资源使用开发,直到下次请求。那这里面需要思考几个问题:-,当图书馆关闭资源开放,而学生还没有尽数归还书籍时,会造成什么样的问题?二,如果学生们都还完书,但是图书馆再次向学生所要书籍资源时会出现什么问题?
这是项目内存管理方面两个最为常见的问题,第一个问题称之为“内存泄漏”,意思是没有废弃或者说没有释放已不再使用的内存资源,第二个问题称之为“过度释放”,意思是再次释放已经释放掉的内存资源。这两个问题最为严重的是第一种,因为其并不会抛出什么异常,这样的结果将导致内存的不合理分配,极大程度上的影响app性能,而第二种往往会导致程序崩溃(crash),崩溃情况为再度废弃已经废弃的对象时崩溃,访问已经废弃的对象时崩溃,以下代码将展现过度释放问题。
/*
* 开辟内存空间,生成并持有对象
*/
id obj = [[NSObject alloc]init];
/*
* 释放obj对象
*/
[obj release];
/*
* 过度释放对象,程序将抛出异常
*/
[obj release];
控制台输出日志:malloc: *** error for object 0x7fa3e86102c0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
为解决这两个问题,编写者必须明确对象的使用周期,如事例所示,在图书馆至少存在一名学生使用图书资源时保持开放状态,而在无人借书时保持关闭状态。其运行逻辑为。当班级组织阅读活动时,管理员(编写者)向图书馆请求内存资源。之后有学生前来借书,管理员对该学生进行纪录并分配其内存资源。活动结束后,学生们归还图书,管理员对学生归还情况进行纪录,释放其持有资源。最后归还图书时,管理员确认之后,关闭对资源的开放。为了能够很好的纪录学生的借还情况,这里面引入了一个管理员的计数技术用以计算可用的图书资源,以及使用资源情况。接下来再透过这个例子的延伸解释这一技术的运作实现。班级向图书馆发送使用图书资源的请求,第一名学生向图书馆借书,资源计数加1。计数值从0变为1,因此要开放资源。第二名学生向图书馆借书,需要资源加1。计数值由1变成2。第三名学生再次向图书馆借书,需要资源再次加1。计数变成3,第四名,第五名依次类推成n。当有学生首先完成阅读之后,需要归还书籍,每归还一本图书时计数减1,那么当第一名学生归还时,计数由n减1。直到最后一名学生归还书籍的时候,计数变为0,图书馆关闭对于此次活动的资源开放。如图1.1所示。
图1.1 引用计数演示图
通过上例可以知道,计数技术可以更加明确资源使用情况,进而更好的管理内存。在objective-c中,内存就是这个图书馆,而学生则被成为“对象的使用环境”,班级活动就是对象,每个图书馆内的图书都是有限的,计算机的资源也是一样,所以尽可能的有效使用资源显得尤为重要。那么在objective-c是怎么处理这些事情呢?
在iOS中可以分为MRC(Manual Retain Release.手动释放),以及iOS 5之后引入的ARC(Automatic Reference Counting,自动引用计数),两种内存管理机制。而在Mac OS X 10.8系统之前还有“Garbage Collector”(垃圾回收机制),但这里面的回收机制与java中的并不相同,它是后台有一个线程负责检查已经不再使用的对象,然后释放,这就会带来两个很大的问题,一个是由于线程一直运行,会影响到cpu的使用效率,二是会造成内存释放迟缓,或者内存泄漏。
本节简单的介绍了一下objective-c的内存管理,了解了引用计数,以及管理的几种方式,接下来将着重地对内存管理进行分块式详细讲解。