iOS 内存分析

iOS 内存分析

Memary Guage increase

​ 最近在做关于APP 内存方面的分析,去尽量优化iOS 侧 APP 的内存。原本使用的是之前自己掌握的方式,比如 Memory leaks , Memory Allocations 每一项工具都有针对性的内容,在进一步优化的时候发现了原来可以使用终端方式来查询问题。一个对于自己全新的领域。

​ 引述一下关键字:iOS Memory Deep Dive WWDC2018

​ WWDC2018 , 2018年 。大概如果是苹果开发铁杆粉都已经悉数掌握。但是很多开发者似乎对这块儿知识都了解较少,如何具体使用也不一定都能掌握。我这儿整理一下对自己查找问题中的一些相关性,也顺带做一下总结,提醒一下自己。

前言

​ 利用自己在实际开发中遇到的相关问题来具体讲解如何在iOS中做内存分析,怎样去针对性优化。

  • 怎样去观察内存占用

  • 需要卸载掉哪些内存

怎样观察内存

​ 大家都在Xcode 下经常开发,Xcode Memory gauge 这个界面大家应该都不会陌生

Memary Guage

​ 在当前界面,能够提供数字,百分比,内存使用危险程度的通用观察界面。针对于平常查看内存占用大小比较方便,但是对于内存问题,这块儿能提供的内容相当有限。但是能够提示开发者内存占用的波动,从而引起关注。

iOS 内存介绍

iOS Memory Deep Dive 讲了关于iOS 在内存方面的使用和统计方式。提到了在iOS 操作系统中,内存的统计方式是按照分页的方式。内存又会被细分为 物理内存 和虚拟内存。 APP 的运行是一定要基于内存之上的,物理内存和虚拟内存的主要作用如下。

物理内存:设备运行时为操作系统和各种程序提供临时储存空间

虚拟内存:为每一个进程提供了一个一致的、私有的地址空间;其主要作用是:保护了每个进程的地址空间不会被其他进程破坏,降低内存管理的复杂性。 虚拟内存是进程运行时所有内存空间的总和,并且可能有一部分不在物理内存中。

​ iOS系统是按页分配内存的,每个page通常是16KB

1
Memory in use = Number of pages * Page size

​ iOS内存可以分为clean memory和dirty memory。当用户(也就是程序员)申请分配内存时,系统只会对这块内存进行标记,这时只会分配虚拟内存,而不会分配物理内存,此时内存是clean memory。当对这块内存进行数据填充时,才会分配物理内存,内存变为dirty memory。

dirty_memory
1
Memory Footprint = Dirty Memory + Compressed Memory

针对内存问题,我们考虑的重点也是去减少 Dirty Memory

具体查找步骤

根据已知的信息,尝试去实践一下如何查找内存消耗,这次使用命令行方式。

以第一张图 27.8M 为例。首先修改 iOS Scheme , 勾选 Malloc Stack Logging 并选中为 Live Aloocations Only

ios_scheme

然后就是运行中等待时机到来,点击Debug Memory Graph 得到内存图。可以通过 File --> Export Memory Graph到处文件到指定位置。

1
2
#终端执行下面代码
$ vmmap -summary memory.memgraph # 首先获取内存分配的概况,使用这条命令可以获得
vmmap_summary

从我们已知的信息可以知道 , Dirty Memory 是我们关注的重点。于是发现了 REGION TYPE 是 MALLOC_LARGE

1
$ vmmap -verbose memory.memgraph | grep "MALLOC_LARGE"  #获取详细的关于内存分配的 在归属于 “MALLOC_LARGE” 这里的内容

vmmap_verbose

从图中我们可以容易的发现,内存地址为 0x1146e4000 。 在这样的情况下,我们可以借助于另外一个命令 malloc_history

1
$ malloc_history memory.memgraph -fullStacks 0x1146e4000   # 获取地址块儿的堆栈信息
malloc_history

根据我们查到的调用堆栈,我们发现是因为 new 操作,导致了内存分配,源头应该在于 InstanceDemo 这个类的构造函数。

source_code

贴上源码,是这里引起的内存分配无疑。我们同时也发现,Dirty memory 也是 9.8M. 如果我们不给数组赋值呢?

我们注释掉数组赋值,重新走一遍儿上面的流程。

vmmap_summary_new

于是发现了,同样 MALLOC_LARGE 中的 VIRTUAL SIZE 是 10M , 但是DIRTY SIZE 只剩下了 208K

如果我们细跟入进去会发现

malloc_history_new

是同样能够查到内存分配的位置。但是因为只有内存申请,没有使用,分配的区域被放在了虚拟内存,所以Dirty MEMARY 并没有相应标记。

在查询内存问题的时候还有另外一个命令可以使用,就是

1
$ leaks -traceTree  0x1118cc000 memory_new.memgraph

leaks_tool

通过这个命令可以知道 m_instance 被持有引用,可能会出现内存泄漏。

Demo 依旧会提供,主要对内存如何分析和查找可能性提出一些方法。 我们同时还可以通过Xcode 提供的 VM Tracker 等工具用来具体指向我们怀疑的点。一般来讲,图片资源占用的内存会比较大,如果作为优化的方向,首选见效处理就是规范化图片资源。