简介: 一般APP只需要关注前台内存过高的系统强杀FOOM,高德地图有不少用户使用后台导航,所以也需要关注后台的内存过高导致的系统强杀BOOM,且后台强杀较前台强杀更为严重。为了提升用户体验,内存治理迫在眉睫。
背景根据Apple官方WWDC的回答,减少内存可以让用户体验到更快的启动速度,不会因为内存过大而导致Crash,可以让APP存活的更久。
对于高德地图来说,根据线上数据的分析,内存过高会导致导航过程中系统强杀OOM。尤其区别于其他APP的地方是,一般APP只需要关注前台内存过高的系统强杀FOOM,高德地图有不少用户使用后台导航,所以也需要关注后台的内存过高导致的系统强杀BOOM,且后台强杀较前台强杀更为严重。为了提升用户体验,内存治理迫在眉睫。
原理剖析OOM
OOM是Out of Memory的缩写。在iOS APP中如果内存超了,系统会把APP直接杀死,一种另类的Crash,且无法捕获。发现OOM时,我们可以从设备->隐私->分析与改进->分析数据中找到以JetsamEvent开头的日志,日志里面记录了很多信息:手机设备信息、系统版本、内存大小、CPU时间等。
Jetsam
Jetsam是iOS系统的一种资源管理机制。不同于MacOS、Linux、Windows等,iOS中没有内存交换空间,所以在设备整体内存紧张时,系统会将一些优先级不高或者占用内存过大的直接Kill掉。
通过iOS开源的XNU内核源码可以分析到:
每个进程在内核中都存在一个优先级列表,JetSam在受到内存压力时会从优先级列表最低的进程开始尝试杀死,直到内存水位恢复到正常水位。
Jetsam是通过get_task_phys_footprint获取到phys_footprint的值,来决定要不要杀掉应用。
Jetsam机制清理策略可以总结为以下几点:
单个APP物理内存占用超过上限会被清理,不同的设备内存水位线不一样。
整个设备物理内存占用受到压力时,优先清理后台应用,再清理前台应用。
优先清理内存占用高的应用,再内存占用低的应用。
相比系统应用,会优先清理用户应用。
Android端为Low Memory Killer:
根据APP的优先级和使用总内存的多少,系统会在设备内存吃紧情况下强杀应用。
内存吃紧的判断取决于系统RSS(实际使用物理内存,包含共享库占用的全部内存)的大小。
关键参数有3个:
1)oom_adj:在Framework层使用,代表进程的优先级,数值越高,优先级越低,越容易被杀死。
2)oom_adj threshold:在Framework层使用,代表oom_adj的内存阈值。Android Kernel会定时检测当前剩余内存是否低于这个阀值,若低于则杀死oom_adj ≥该阈值对应的oom_adj中,数值最大的进程,直到剩余内存恢复至高于该阀值的状态。
3)oom_score_adj:在Kernel层使用,由oom_adj换算而来,是杀死进程时实际使用的参数。
数据分析phys_footprint获取iOS应用总的物理内存,具体可以参考官方说明iOS Memory Deep Dive.
std::optional<size_t> memoryFootprint() { task\_vm\_info\_data\_t vmInfo; mach\_msg\_type\_number\_t count = TASK\_VM\_INFO_COUNT; kern\_return\_t result = task\_info(mach\_task\_self(), TASK\_VM\_INFO, (task\_info_t) &vmInfo, &count); if (result != KERN_SUCCESS) return std::nullopt; return static\_cast<size\_t>(vmInfo.phys_footprint); }Instruments-VM Tracker可以用来分析具体内存分类,比如Malloc部分是堆内存,Webkit Malloc部分是JavaScriptCore占用的内存等。需要注意的是每个分类的内存值 = Dirty Size + Swapped。
通过Instruments VM Tracker抓取导航中内存分布进行对比分析。导航前台静置时,高德地图的总内存数值非常高,其中IOKit、WebKit Malloc和Malloc堆内存为内存占用大头。
在分析过程中可以使用的工具很多,各有优缺点,需要配合使用,相互弥补。我们在分析的过程中主要用到Intruments VM Tracker、Allocations、Capture GPU Frame、MemGraph、dumpsys meminfo 、Graphics API Debugger、Arm Mobile Studio、AJX 内存分析工具、自研Malloc分析工具等。
IOKit内存为地图渲染显存部分。
WebKit Malloc内存为AJX JS业务内存。
Malloc堆内存,我们通过Hook Malloc分配内存的API,通过抓取堆栈分析具体内存消费者。
治理优化
根据上面的数据分析,很容易做出从大头开始抓起的思路。我们在治理过程中的大体思路:
分析数据:从内存大头开始,分析各内存归属业务,以便业务进一步分析优化。
内存治理:优化技术方案减少内存开销、高低端机功能分级和智能容灾(即内存告警时通过功能降级等策略释放内存)。
分而治之