移动开发技术前沿待读清单人猿星球

内存策略

2018-06-08  本文已影响219人  sindri的小巢

原文地址

尽管在进入后台之后,程序的工作受到大幅度的限制,但是我们总是不会希望应用突然被操作系统杀死,中断了重要的后台工作。后台应用被杀死,影响的不止是用户体验,比如正在播放的音乐戛然而止,正在导航的语音意外中断。由于操作系统杀死后台应用并不是任何一种异常、或者运行错误,应用失去响应意外的能力,极有可能破坏了单次运行中积累的重要数据。因此如何减少应用在后台运行被杀死,是一个值得思考的问题

后台应用如何被杀

抛开因为应用在后台停留太久被杀死之外,因为内存问题被杀死是最重要的原因。内存和其他硬件资源有很大的不同,区别在于:

当资源需求量多于资源所能供应的时,CPU表现为性能下降,而操作系统会为了回收内存杀死后台应用

我们可以把设备内存分成四块区域,包括systembackgroundforegroundfree四部分。

假设设备刚开机,用户直接打开你的应用,这时候设备的内存不包括background部分:

应用在这时退出前台,由于此时还有足够的free内存可分配,系统暂时不会收回内存:

然后用户打开了一个新的应用,但是新的应用需要大量内存,此时超出了设备的可用内存量:

于是系统向你的应用发出memory warning通知,系统回收了暂时不用的内存,然后有足够的内存给新应用使用:

又或者根本没发出warning,你的应用直接被杀死:

内存警告

内存警告memory warning会在系统察觉到可能没有更多的free内存使用时发出,包括通知和代理两种方式的调起。通常来说,开发者和系统都会针对warning做应对措施,根据处理方的角色不同,我们可以将其分为主动策略被动策略

内存分类

在了解两种应对策略的差异之前,我们需要了解对于每一个运行的应用来说,可被系统自动清除的内存分为两类:(此处内存限制为主动分配,可随时释放的内存)

从内存的分类来看,减少Dirty数据的数量,增加Purgeable可以减少内存使用的压力

被动策略

之所以要先说被动策略,是因为操作系统在发出warning之前,已经做了一些工作来尝试解决问题,只有了解这些才能更好的帮助我们解决问题

主动策略

从操作上来说,purgeable的数据都需要开发者维护,更像是一种主动性的机制。但这个机制在内存不够用时,会被系统自动收回内存,而无需开发者进行更多额外的工作,因此被我归类到被动策略。主动策略更应该是接收到memory warning后,开发者进行的工作:

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    /// release data cannot keep the application running
    [self.database close];
}

- (void)didReceiveMemoryWarningNotification: (NSNotification *)notification {
    /// release data cannot keep the application running
    [self.dataSource removeAllObjects];
    [self.images removeAllObjects];
    [self cleanAllAnimatorViews];
}

处理warning几乎是开发者的唯一有效手段,但是这种手段也并不完全可靠,如果依赖于系统发出的内存警告,存在几个风险点:

因此,即便处理警告几乎是唯一手段,依旧还得思考其他方式。假如我们从将一部分数据映射到磁盘上,应用可以以最小的内存占用运行

文件映射

文件映射不是万能药,每次修改数据都会同样更新到磁盘相同位置,即便SSD的存取能力已经很强大了,但依旧是不小的开销。你的数据应该总是满足这些要求,才考虑使用文件映射:

这些条件决定了文件映射这种方式并不是适用于所有数据,基本适用于配置文件、图像数据、文本数据等,而这些数据也往往是占用内存的大头

另外如果数据量很大时,将数据整合成一个大数据段。同样数据大小的情况下,系统处理多块文件映射的内存效率要低的多。另外太多的虚拟内存块,也会导致系统强行杀死应用。NSData允许我们使用options提供文件映射的方式:

typedef NS_OPTIONS(NSUInteger, NSDataReadingOptions) {
    NSDataReadingMappedIfSafe =   1UL << 0,
    NSDataReadingUncached = 1UL << 1,
    NSDataReadingMappedAlways API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0)) = 1UL << 3,
};

其他

由于苹果的沙盒机制,我们过去总是更多的关注于应用内对于内存的使用情况,比较少关注应用在后台运行时可能遇到的内存问题,引用WWDC视频上苹果工程师的一句话:

你应该总是认为:在你应用之外的其他东西,会对你保持敌意并且有毁灭你的可能

因此,我们要学习如何合理的运用内存使用策略,来抵抗应用外的进攻。当然,最重要的是,我们可以理直气壮的告诉QA:哼,应用的内存使用降下来了!

上一篇 下一篇

猜你喜欢

热点阅读