由于在IOS中虚拟内存系统不会采用页置换的方式来获取请求内存,取而代之的是它通过移除应用程序中的强引用来释放一些内存资源,我们知道强引用在IOS中表示拥有关系,只要有至少一个变量拥有这个对象,那么对象就不会被释放,当然IOS中没有类似Java或.NET的垃圾回收机制,所以我们需要手动来释放对象的引用。当然在ARC中,编译器会在编译阶段为我们插入这段释放代码。释放其实就是减少引用计数,有关于引用计数在内存管理中的应用,我会在另一篇文章中做描述。
当可用虚拟内存页的数量低于系统规定的临界值时,系统会尽可能自动释放那些只读的内存页,同时也会向当前运行的应用程序发送一个内存不足的警告。当你的应用程序接收到这个消息通知时,我们应该重视它,一旦我们接收到这样的消息,我们的应用程序必须尽可能的移除尽可能多的对象的强引用。例如,我们可以清除那些可以再次读取到的数据缓存。
UIKit为我们提供了很多方式来接收这些内存管理通知,如下所示:
- 实现应用程序代理的
applicationDidReceiveMemoryWarning:
方法。(AppDelegate) - 重写自定义控制器的
didReceiveMemoryWarning
方法。(UIViewController) - 通过注册接收
UIApplicationDidReceiveMemoryWarningNotification
消息通知。(NSNotificationCenter)
一旦接收到内存警告通知,我们的处理器方法应该马上移除一些对象的强引用。控制器会自动移除那些当前不在屏幕上显示的对象引用,但是我们最好还是需要覆写一下didReceiveMemoryWarning
方法来移除一些我们控制器不需要的额外的对象引用。例如:当导航控制器Navigation Controller接收到内存警告后,它会首先判断它所包含的控制器是否存在一个非空View,然后会询问是否这个View可以被销毁(例如当前需要显示在界面上的View原则上不可以被销毁),如果可以被销毁,那么系统会直接回收这个View所占用的内存,当然这个View呈现所依赖的数据这个时候最好通过代码移除(例如:self.data = nil;),View都不存在了,那些数据也就没有存在的必要了(ViewDidUnLoad处理,新版本已经废弃了该方法)。下面引用苹果官方的一个流程图:
如果我们仅仅只有很少的一些可清除的对象资源,我们可以通过注册 UIApplicationDidReceiveMemoryWarningNotification
消息通知来移除这些引用。如果我们有很多可清楚的对象并且期望选择性的清除一些,那么我们最好使用应用程序代理来决定哪些对象该保留哪些对象该清除,那么实现 applicationDidReceiveMemoryWarning:
方法将会是一种更好的选择。
和系统应用程序一样,我们的应用程序应该总是处理内存不足的警告,即使在我们测试时没有接受到这些警告消息。当系统检测到内存不足时,系统会将内存不足消息警告分发给所有在运行中的应用程序,有可能会直接终止掉某些后台应用程序来释放内存压力。如果还没有足够的内存给我们应用程序使用,系统会认为我们的应用程序可能发生了内存泄露或者是使用了太多的内存,然后系统会无情的终止我们的应用程序。听起来真得很残暴。