内存优化包括OOM趋势、泄漏分析、大对象和单设备内存详情,可以帮助您更好的进行内存优化。
在OOM趋势中,提供了内存泄漏的指标分析。除了核心指标OOM次数、OOM率、影响用户数、影响用户比例,还提供进一步分析OOM的扩展指标,如:App占用内存大小、App占用内存比例。
您可以通过以下筛选条件进行数据筛选。
说明
OOM类型包括:
OOM趋势图展示了筛选条件下OOM指标的趋势。指标数据的右侧可以查看与上一周期相比OOM的数据变化。
.png
文件类型的数据概览。指标说明:
指标 | 说明 |
---|---|
OOM次数 | 筛选条件下发生OOM的次数(PV) |
OOM率 | 筛选条件下的OOM次数/筛选条件下的总launch次数 |
影响用户数 | 筛选条件下OOM问题影响的用户数(UV) |
影响用户比例 | 筛选条件下发生OOM错误的去重UV数/筛选条件下的去重总UV数 |
除了大盘中提供的默认指标外,OOM还支持扩展指标。
上报字段 | 指标名称 |
---|---|
app_memory_rate | APP占用内存比例 |
app_memory | APP占用内存大小 |
上报字段 | 指标名称 | 获取方式 |
---|---|---|
total_pss_background | 物理内存(后台) | Debug.MemoryInfo.getTotalPss() |
total_pss_foreground | 物理内存(前台) | Debug.MemoryInfo.getTotalPss() |
java_heap_background | Java使用内存(后台) | Runtime. getRuntime ().totalMemory()-Runtime. getRuntime ().freeMemory() |
java_heap_foreground | Java使用内存(前台) | Runtime. getRuntime ().totalMemory()-Runtime. getRuntime ().freeMemory() |
graphics_background | 显存(后台) | Debug.MemoryInfo.getMemoryStat("summary.graphics") |
graphics_foreground | 显存(前台) | Debug.MemoryInfo.getMemoryStat("summary.graphics") |
vm_size_background | 虚拟内存(后台) | /proc/进程pid/status |
vm_size_foreground | 虚拟内存(前台) | /proc/进程pid/status |
java_heap_background_used_rate | Java内存使用率(后台) | java_heap_background/Runtime. getRuntime ().maxMemory() |
java_heap_foreground_used_rate | Java内存使用率(前台) | java_heap_foreground/Runtime. getRuntime ().maxMemory() |
dalvik_pss_background | Java物理内存使用(后台) | Debug.MemoryInfo.dalvikPss |
dalvik_pss_foreground | Java物理内存使用(前台) | Debug.MemoryInfo.dalvikPss |
native_pss_background | Native物理内存使用(后台) | Debug.MemoryInfo.nativePss |
native_pss_foreground | Native物理内存使用(前台) | Debug.MemoryInfo.nativePss |
单击扩展指标名称进入指标详情页面。
内存泄漏指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成内存空间的浪费。内存泄漏有时不严重且不易察觉,以至于开发者不知道存在内存泄漏、泄漏积累过多、内存耗尽等情况,最终导致OOM。
泄漏分析中提供了导致泄漏的对象类型列表和详情分析,在这里可以逐一分析那些导致严重内存泄漏的对象。
您可以通过以下筛选条件进行数据筛选:
时间、系统、系统版本、APP版本、机型、APM SDK版本、issue状态、处理人、标签、泄漏详情。
单击泄漏趋势列表中的泄漏说明,进入泄漏详情页面。您可以查询泄漏摘要、详细信息、泄漏趋势、泄漏分布、详细信息、引用链和符号表。
摘要中可以查看泄漏的发生次数、影响用户数、影响用户比例、最近上报时间、最近发生时间、首次发生时间,还可以查看和设置泄漏的状态、处理人和标签。
泄漏分布中支持根据不同维度筛选数据,默认按照设备机型、设备系统版本、rom信息、下载渠道筛选数据。您可以单击选择维度自定义分布维度。
泄漏趋势中根据筛选条件展示数据。默认按照发生次数查看数据的趋势,您可以切换成按照影响用户数查看数据的趋势。
详细信息中可以查看泄漏的异常数据的详细信息。
引用链会展示泄露的Activity类和具体GC Root之间的具体引用关系。把引用关系断掉可以解决泄露问题。所有泄露都应该被优化解决。
大对象是指“单个大小超过1000KB的对象”或“个数超过50且内存总大小大于10000KB的类”。大对象是内存占用的主力军,是优化内存过程中重点分析的部分。
大对象列表中提供了占用内存过大的大对象以及数量众多聚合而成的小对象,帮助您更准确地了解内存被哪些对象占用。
您可以通过以下筛选条件进行数据筛选:
时间、系统版本、APP版本、机型、大对象类型、APM SDK版本、issue状态、处理人、标签、卡顿详情。
单击大对象分析列表中的大对象详情,进入大对象详情页面。除了可以查询大对象摘要、详细信息、大对象趋势、大对象分布、详情信息、引用链、持有对象和符号表。
摘要中可以查看大对象的发生次数、影响用户数、影响用户比例、最近上报时间、最近发生时间、首次发生时间,还可以查看和设置大对象的状态、处理人和标签。
大对象分布中支持根据不同维度筛选数据,默认按照设备机型、设备系统版本、rom信息、下载渠道筛选数据。您可以单击选择维度自定义分布维度。
大对象趋势中根据筛选条件展示数据。默认按照发生次数查看数据的趋势,您可以切换成按照影响用户数查看数据的趋势。
详细信息中可以查看大对象的异常数据的详细信息。
引用链会展示大对象到具体GC Root的具体引用关系,可以判断引用关系是否合理,是否可以断掉。
注意
文件路径最多支持展开1000层。
持有对象会展示大对象具体引用了哪些对象导致自身占内存较大,可以判断是否可以通过优化持有对象来优化内存占用。
例如,图中List缓存对象过多,并且缓存对象过大导致内存占据大,可以通过清除缓存对象来达到优化的目的。
在单设备内存详情中,可直接分析单台设备的内存问题。iOS提供了直接精准分析单台设备的内存引用树、支配树、实例等,Android可下载查询其原始数据。
您可以通过以下筛选条件进行数据筛选。
.xlsx
文件格式的设备内存信息。.hprof
文件内容。聚类列表展示了App内存的总览,内存节点按照类型进行聚合,通过排序等方法可以帮助您快速确定App中内存的大致分布,初步暴露问题。
说明
列表中的参数说明:
参数 | 说明 |
---|---|
类名 | 标识内存节点类型名称。
选择不同聚合方式,数量、SHALLOW SIZE、RETAIN SIZE这些列数据都会发生变化。同时,区域②实例列表的显示信息也会发生变化。 |
数量 | 此种类型的节点数量。 |
SHALLOW SIZE | 此种类型节点的所有实例占用内存之和。 |
RETAIN SIZE | 此种类型节点的所有实例,及其所支配的节点,占用内存之和(支配定义可以查看附录)。 |
实例列表展示了聚类列表中某个集合的所有节点。通过一些分析手段对一类节点打标签,可以根据用途对节点进行分类,也可以单击某个节点以查看某个具体实例的详细信息。
基本信息展示了一个节点的基本信息,包括节点的大小、地址、类型、是否为泄漏、标签等等。
参数说明:
参数 | 说明 |
---|---|
类名 | 当前节点的类名,以类名+大小的形式展示。 |
节点类型 | 节点所属的类型。 |
Ptr | 节点的地址。 |
VMType | 虚拟内存类型,Heap或者具体的VM类型。 |
VMSize | 内存大小,对于不同类型的节点,该数据有不同的口径。
|
RetainedSize | 节点支配的所有节点的内存大小之和。 |
是否为Abandoned问题 | 当前节点是否为Abandoned Memory(如果不了解Abandoned定义,可以参考附录)。 |
是否为泄漏 | 当前节点是否为内存泄漏的节点。 |
常见的VM类型:
VM类型 | 说明 |
---|---|
| 栈内存,每个线程会有自己的线程栈以及TLS等数据,这些数据就保存在VM: Stack中,这个节点的孩子就是栈引用的临时变量以及TLS等数据,包括AutoreleasePool的入口也在此,可以根据大小判断该线程的类型,通常主线程为1008KB,GCD线程以及默认的线程为544KB,其他大小自行按业务映射。例如,TTPlayer的线程某些为160KB。 |
| ImageIO使用到的数据,通常是图片,使用 |
| CoreGraphics使用到的栅格数据,通常是图片,比如SDWebImage等常用框架都会使用CoreGraphics对图片进行绘制。在重度使用网络图片的App中,该类型VM通常是内存使用的主要类型。 |
| WebKit的堆内存,WebKit使用自己的bmalloc对内存进行管理而不使用libmalloc,跨端方案(小游戏、小程序、RN、Weex)和H5会大量使用该类型内存。 |
| 跨进程、CPU与GPU共享数据的关键结构,通常是纹理、framebuffers、图片,常见于特效渲染、视频录制。 |
| iOS驱动相关的内存分配,常见于纹理(比如Metal的一些纹理分配)存储等场景,和IOSurface一样,在特效渲染、视频录制等情况下会大量出现。 |
| CoreAnimation的内存使用,常见于Layer的BackingStore,如果图层过多,该类型内存会过高。 |
| SQLite分配的Page Cache。 |
| 多种可能,直接使用VM Alloc申请的即是该类型内存,Data段内存也属于该类内存。 |
图中左图为引用图,右图为其相应的支配树。
如果从根节点M到节点B必须经过节点A,则节点A支配节点B,离节点B最近的支配点,就是其在支配树上的父亲。
支配树中,如果父节点释放,那么父节点的所有子节点都被释放。
引用树展示当前节点相关的引用关系,父节点是当前节点在引用树中的父节点,子节点是当前节点在引用树中的子节点。
支配树展示当前节点相关的支配关系,父节点是当前节点在支配树中的父节点,子节点是当前节点在支配树中的子节点。
通过引用树和支配树,可以快速定位节点最终被什么业务对象所引用,便于定位问题。
收起Heap父节点:压缩引用树中没有符号的Heap父亲节点。勾选后,将自动回溯,寻找当前节点到root节点的各条路径中第一个有符号意义的节点,然后将路径中的Heap节点隐藏,把这些有符号意义的节点展示在父节点列表中,可以帮助您快速找到有意义的业务对象。
聚合展示:把相同类型(类+大小)的节点聚合在一起展示,并在括号中显示此类节点的数量。
关系说明:引用树每一条节点都有一个表示引用关系的按钮,通过颜色表示不同的引用类型,显示文本为变量名或偏移,assign表示偏移0,Indirect表示间接引用关系。单击按钮可以切换节点,同时③基本信息和④引用树和支配树都将变为该节点对应的信息。
关系说明:
参数 | 说明 |
---|---|
Indirect Relation | 非直接引用,当勾选收起Heap父节点后,会出现此类节点。 |
Weak Ref | 弱引用。 |
Strong Ref | 强引用。 |
Unknown/Assign | 未知引用关系或assign。 |
环:引用树里单击父节点进行回溯的过程中,某些节点可能会出现删除线,说明在回溯的过程中该节点曾经出现过环,可以在⑤回溯路径中查看生成环的路径中出现了哪些节点。
节点信息:引用树和支配树的每一个节点的组成:类名+大小+(地址)+(支配大小,不包括自身内存) + 引用关系按钮。
回溯路径记录了从一个节点往祖先进行回溯时经过的路径,可以帮助您理清一个对象是如何被业务对象所引用的。
术语 | 说明 |
---|---|
Abandoned和泄漏 | 苹果官方文档介绍了iOS APP的内存分类:
APMPlus MemoryGraph采用类似GC的泄漏判定方法,如果从根节点出发无法到达节点A,则节点A泄漏,如果一个集合中的节点自己组成了一个独立的图,而且不与主图连通,则该集合为Abandoned。泄漏的判定不参考强弱引用关系,只参考可达性。 |
数据口径 | MemoryGraph记录了APP的所有内存状态和关系:
|
MemoryGraph的使用方式并不是固定的,以下流程只是对于一些常见情况的惯用方法,可以根据自己的理解来灵活运用,让MemoryGraph成为帮助您解决内存问题的利器。