iOS内存分析之Memory Graph

·  阅读 7833
iOS内存分析之Memory Graph

1.Memory Graph是什么

Memory Graph是在Xcode8上推出的一个新特性。用来生成应用程序中对象分配的内存图。

2.Memory Graph用来做什么

  • Memory Graph可以帮助我们找到循环引用和内存泄漏,正在使用的内存以及每个区域的大小。
  • Memory Graph显示应用程序使用的内存的位置,以及这些使用内存之间的引用关系。

3.如何使用Memory Graph

打开配置

  

注意点:

  1. 启用Malloc Stack后,Memory Graph会显示分配该节点时记录的堆栈跟踪。使用此信息将Memory Graph中的内存分配与源代码中的函数和方法相关联。如果没有勾选 Malloc Stack 在调试的时候,在右侧是看不到调用的堆栈信息。

  2. 勾选 Malloc Stack 之后内存会相应的增高,如果不调试可以关闭该选项。

  3. 建议选择 Live Allocations Only 如果选择 All Allocations and Free History 会出现一些额外的影响因素。

打开方式

通过单击Xcode工作区底部调试区域中的 Debug Memory Graph 按钮来生成应用程序中对象和分配的内存图。

​ 点击Debug Memory Graph暂停应用执行,展示如下:

  • 在左侧debug navigator展示了app的heap contents
  • 在中间部分是对象的引用关系。
  • 在最右侧是展示了当前对象的调用栈回溯。

Memory Graph显示应用程序正在使用的内存区域以及每个区域的大小。图中的节点代表一个对象(object)、一个堆分配(heap allocation)或内存映射文件(memory-mapped file)。节点之间的连接,通过箭头连接,显示一个内存区域引用另一个对象。

Tips:

为了帮助我们更快的分析内存泄漏,我们可以在左侧的debug navigator进行筛选只展示leaks的内容。

可以将我们生成的memory graph进行导出,选择 file > export Memory Graph 共享给团队内的人员使用和分析探索。我们还可以使用命令行工具进行分析,主要的指令有leaksheapvmmapmalloc_history等。

4.项目实际应用及分析

导出所对应的Memory Graph使用命令行的形式进行分析。主要分析内存泄漏大内存占用。

Memory FootPrint


Apple推荐我们使用FootPrint命令查看一个进程占用的大小。关于什么是 footprint,在官方文档 Minimizing your app’s Memory Footprint 里有说明:

FootPrint =  Dirty memory + Swapped memory(Compressed memory)
Refers to the total current amount of system memory that is allocated to your app.
复制代码

iOS中内存分为两种:

  • Clean memory

    • 内存映射文件(Memory mapped files )
    • 数据段常量/代码段数据 (System Frameworks)
  • Dirty memory

    • (堆上分配的内存) All heap allocations

    • (解码图像缓冲区) Decoded image buffers

    • Frameworks

      Clean memory在系统内存紧张的时候可以从page中换出,当再次访问的时候可以从磁盘中进行读取。Dirty memory是无法换出的

在iOS7时Apple引入了Compressed memory ,即系统可以把最近最少使用的Dirty memory进行压缩,这样可以腾出一些pages供使用,当再次需要访问内容时,系统将其解压,这时,原来内容占多少pages,解压后同样会是相同数量的pages

1.内存分析

先通过vmmap看一下内存的摘要图:

    vmmap -summary memGraph.memgraph
复制代码

  • 从这个图中可以看到当前app的一个内存分布情况,footPrint占用的内存大小为26.1M,根据footprint的计算方式可以知道,我们需要关注的是dirty size + swapped size这两列的数据。首先看下对应的Region type分别代表的是什么内存。

    • CG raster data(光栅化数据,也就是像素数据。注意不一定是图片,一块显示缓存里也可能是文字或者其他内容。通常每像素消耗 4 个字节)
    • Image IOIOSurface(图片编解码缓存)
    • maclloc_ 开头的是我们自己通过malloc进行创建的内存占用。这部分内存在所谓的Heap上。
    • IOSurface 在CoreGraphics、OpenGLES、Metal之间传递纹理数据。简单理解为IOSurface,为CPU和GPU直接搭建了⼀个传递纹理数据的桥梁。

那么看下具体的是哪些类占用了内存。需要具体来分析一下。

从里面看到都是CG raster data 占用比较大。具体在哪里被引用了,需要看一下具体的调用栈。首先筛选出来CG raster data的内存信息,包括它的地址、尺寸以及所在Heap Zone等等信息。我们可以在这里找到我们的目标。

vmmap memGraph.memgraph |  grep 'CG raster data'

malloc_history -fullStacks memGraph.memgraph 0x10ee24000
复制代码

通过vmmap 筛除所有关于CG raster data内存情况。然后通过malloc_history -fullStacks拿到对象的详细调用堆栈。

可以看出是在SDWebImage对图片的解码数据做了缓存。建议在使用的时候设置缓存的图片数量和大小。也可以根据具体的情况关掉解码的缓存。或者在加载大图的时候使用ImageIO的形式进行加载。

2.内存泄漏

通过leaks筛除所有的内存泄漏

leaks memGraph.memgraph
复制代码

从上图中可以看出,是AFHttpSessionManager出现了内存泄漏,从引用的关系中可以看出,是当前的sessionManager强引用了sessionsessiondelegate同时强引用了sessionManager。解决方案就是我们在调用之前使用weak弱引用sessionManager,当请求完成的时候执行finishTasksAndInvalidate

分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改