Android Memory Tracker原理分析

Memory Tracker原理分析

1. 背景

公司有一个测试项,执行adb shell dumpsys meminfo + pkg命令查看内存信息:

malk@malk:am$ adb shell dumpsys meminfo com.meizu.safe
Applications Memory Usage (in Kilobytes):
Uptime: 103881237 Realtime: 263009590

** MEMINFO in pid 32506 [com.meizu.safe] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap    18894    18832        0        0    32768    20940    11827
  Dalvik Heap     6713     6624        0        0    10615     6519     4096
 Dalvik Other     1485     1484        0        0                           
        Stack      700      700        0        0                           
       Ashmem        2        0        0        0                           
    Other dev        4        0        4        0                           
     .so mmap     2717      136       40       39                           
    .apk mmap    44952        0    35456        0                           
    .ttf mmap       45        0        0        0                           
    .dex mmap     5344        8     1324        0                           
    .oat mmap     2728        0        0        0                           
    .art mmap     2871     2368        4        2                           
   Other mmap     1090        4       64        0                           
   EGL mtrack    12168    12168        0        0                           
      Unknown     1535     1532        0        0                           
        TOTAL   101289    43856    36892       41    43383    27459    15923

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     8996
         Native Heap:    18832
                Code:    36964
               Stack:      700
            Graphics:    12168
       Private Other:     3088
              System:    20541

               TOTAL:   101289       TOTAL SWAP PSS:       41

一直有个疑问,dump信息中EGL mtrack/GL mtrack两项分别代表什么意思?

google官方解释:
EGL memtrack

You will see this column when display driver’s memtrack module is enabled
Before Lollipop5.1, this column is named “Graphics”.
EGL memtrack memory is the summary of all surface buffers(the surface buffer increases to triple buffer after Android 4.1) and the size of the Atlas buffer. 
However, Atlas buffer is actually a shared memory and shouldn’t be accounted into each UI process’ memory usage to overcount the memory usage. 
Both surface buffer and Atlas buffer’s memory quota is reserved in project’s memory estimation, thus the memory usage of these buffers should be separately 
accounted from process’ memory usage. So when you measure process’ memory usage, you can ignore this column.

GL memtrack

You will see this column when display driver’s memtrack module is enabled
Before Lollipop5.1, this column is named “GL”.
HW acceleration memory is partially counted in process PSS. For example, for QCT platform the HW acceleration memory is partially counted in the PSS of /dev/kgsl-3d0 
as we mentioned in the “Gfx dev” section. GL memtrack memory usage calculates the unaccounted /dev/kgsl-3d0 memory regions which PSS value equals 0.
Please be noticed that the summation of GL memtrack and Gfx dev doesn’t reflect the complete HW acceleration memory since the full HW acceleration memory usage 
should be counted with the VSS of /dev/kgsl-3d0. So the “TOTAL” value of dumpsys meminfo is smaller than actual physical memory usage.

只看简介有些难以理解,我想了解它的生成原理,找了半天,发现qualcomm和mtk平台相关代码没有开源,还好samsung开源了代码。

先说明一下这两项的含义:

name description
EGL mtrack gralloc分配的内存,主要是窗口系统,SurfaceView/TextureView和其他的由gralloc分配的GraphicBuffer总和
GL mtrack 驱动上报的GL内存使用情况。 主要是GL texture大小,GL command buffer,固定的全局驱动程序RAM开销等的总和

2. Memory Tracker

2.1 Memory Tracker是什么

Memory Tracker也称memtrack,是一个hal层的库,不同平台库的名称不同,实现方式也有差异。

以samsung平台为例:

Name: memtrack.exynos5.so
File Directory:/system/lib64/hw/
Source code : hardware/samsung_slsi/exynos/libmemtrack/

Memory Tracker 主要目标是能够跟踪以任何其他方式无法跟踪的内存,例如由进程分配但未映射到进程地址空间的纹理内存。
第二个目标是能够将进程使用的内存分类为GL,graphics等。所有的内存大小应该在实际的内存使用情况下,考虑到stride,bit depth,page size等。

EGL mtrack/GL mtrack这两项的数据就是通过memtrack获取的。

2.2 adb shell dumpsys meminfo实现原理

先看一下adb shell dumpsys meminfo +pkg的流程

Android Memory Tracker原理分析_第1张图片

1. Ams在systemserver启动时,创建了meminfo服务,所以才能dumpsys meminfo:

ServiceManager.addService("meminfo", new MemBinder(this));

2.执行dumpsys操作后,会去获取两部分信息:

static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
        jint pid, jobject object)
{
    bool foundSwapPss;
    stats_t stats[_NUM_HEAP];
    memset(&stats, 0, sizeof(stats));

    load_maps(pid, stats, &foundSwapPss);//获取/proc/$pid/smap节点信息

    struct graphics_memory_pss graphics_mem;
    if (read_memtrack_memory(pid, &graphics_mem) == 0) {//获取graphics drivers上报的内存信息
        stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
        stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
        stats[HEAP_GL].pss = graphics_mem.gl;
        stats[HEAP_GL].privateDirty = graphics_mem.gl;
        stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
        stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
    }
}
static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
    char tmp[128];
    FILE *fp;

    sprintf(tmp, "/proc/%d/smaps", pid);
    fp = fopen(tmp, "r");
    if (fp == 0) return;

    read_mapinfo(fp, stats, foundSwapPss);
    fclose(fp);
}
/*
 * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
 * 获取不计算在/proc/pid/smaps里的graphics memory信息
 */
static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
{
    if (!memtrackLoaded) {
        return -1;
    }

    struct memtrack_proc* p = memtrack_proc_new();
    if (p == NULL) {
        ALOGW("failed to create memtrack_proc");
        return -1;
    }

    int err = read_memtrack_memory(p, pid, graphics_mem);
    memtrack_proc_destroy(p);
    return err;
}

3. graphics memory数据类型
graphics memory分为五种类型数据:

  • MEMTRACK_TYPE_OTHER = 0,
  • MEMTRACK_TYPE_GL = 1,
  • MEMTRACK_TYPE_GRAPHICS = 2,
  • MEMTRACK_TYPE_MULTIMEDIA = 3,
  • MEMTRACK_TYPE_CAMERA = 4

我看到libmemtrack中有判断,只接收两种数据,其他数据对应的代码没有找到:

memtrack_exynos.c
    if (type == MEMTRACK_TYPE_GL) {
        return mali_memtrack_get_memory(pid, type, records, num_records);
    } else if (type == MEMTRACK_TYPE_GRAPHICS) {
        return ion_memtrack_get_memory(pid, type, records, num_records);
    }

MEMTRACK_TYPE_GL = GL mtrack,MEMTRACK_TYPE_GRAPHICS = EGL mstrack

2.3 Memory Tracker实现原理

graphics memory的数据是由graphics driver统计的,统计方式会因平台不同而有所差异,即使相同应用,不同平台读取的数据也可能不相同。
Memory Tracker做的事情就是将graphics driver统计好的数据从节点读取并格式化。

以samsung平台为例,memtrack.exynos5.so库做的事情很简单,根据上层传递的type读取对应节点,获取内存信息。

memtrack_exynos.c
    if (type == MEMTRACK_TYPE_GL) {
        return mali_memtrack_get_memory(pid, type, records, num_records);
    } else if (type == MEMTRACK_TYPE_GRAPHICS) {
        return ion_memtrack_get_memory(pid, type, records, num_records);
    }

2.3.1 MEMTRACK_TYPE_GL

如果上层传递的type类型为MEMTRACK_TYPE_GL,对应GL mtrack,说明需要获取的是驱动程序报告的GL内存使用。它主要是GL纹理大小,GL命令缓冲区,固定的全局驱动程序RAM开销等的总和。这些数据储存在/d/mali/mem/目录下的节点中(samsung),由mali库(或者其他平台的渲染库)进行统计。

以samsung平台,com.meizu.safe应用为例,我们查看其数据:

1|m17:/ # ps | grep safe                                                                                                                                                              
system    32459 1174  1849812 127628 SyS_epoll_ 7b483472a0 S com.meizu.safe:MzSecService
system    32506 1174  2904076 225528 SyS_epoll_ 7b483472a0 S com.meizu.safe
m17:/ # 
m17:/ # 
m17:/ # cat /d/mali/mem/32506_76/mem_profile                                                                                                                                          
com.meizu.safe:
Channel: Unnamed (Total memory: 2384536)
  7:                  226 / 14464
  8:                  297 / 47520
  9:                   16 / 6272
 13:                  166 / 684696
 14:                   68 / 601960
 15:                    4 / 79352
 16:                    3 / 98304
 17:                    5 / 327680
 18:                    4 / 524288

Channel: Default Heap (Total memory: 1678048)
 13:                   14 / 60744
 14:                    2 / 27352
 16:                    6 / 196672
 18:                    4 / 749088
 20:                    1 / 644192

Channel: Framepool (Total memory: 0)
 (empty)

Channel: Frame Internal (Total memory: 32768)
 16:                    1 / 32768

Channel: GPU Program (Total memory: 40960)
 16:                    1 / 40960

Channel: EGL Color Plane (Total memory: 4096)
 13:                    1 / 4096

Channel: GLES VAO (Total memory: 0)
 (empty)

Channel: Image Descriptor (Total memory: 352)
  5:                   16 / 256
  7:                    1 / 96

Channel: Texture (Total memory: 6252064)
  6:                    1 / 32
 10:                    1 / 512
 11:                    1 / 1024
 12:                    1 / 2048
 14:                    2 / 18816
 16:                    1 / 51008
 17:                    7 / 716608
 19:                    1 / 266240
 21:                    1 / 1048576
 22:                    1 / 4147200

Channel: Buffer (Total memory: 1204288)
  7:                    1 / 64
 15:                    1 / 24576
 18:                    1 / 131072
 21:                    1 / 1048576

Channel: CRC Buffer (Total memory: 102400)
 13:                    1 / 4096
 16:                    3 / 98304

Total allocated memory: 11699512

分类说明:

name description
Default Heap gpu内部结构的内存分配。是gpu中最基础的内存分配
Framepool framepool是gpu内部的概念,这个channel统计为framepool结构分配的内存。很多函数,例如eglSwapBuffers可能会引起这个channel的内存增加
Frame Internal tiler是gpu内部的概念,这个channel统计为tiler结构分配的内存。很多函数,例如glCreateXXXSurface可能会引起这个channel的内存增加
GPU Program glLinkProgram被调用时,需要分配相应内存来存放shader code,那么这段内存将被记录进GPU Program
Image Descriptor image instance是gpu内部的概念,这个channel统计为image instance结构分配的内存。很多函数,例如glDrawXXX可能会引起这个channel的内存增加
EGL Color Plane 为color planes分配的内部buffer。一些函数,例如gpu的回调函数可能会引起这个channel的内存增加
GLES VAO VAO是一个保存了所有顶点数据属性的状态结合,它存储了顶点数据的格式以及顶点数据所需的VBO对象的引用。
Texture 纹理
Buffer glBufferData被调用时,需要分配内存来存放要导入的data,这段内存将被记录进Buffer
CRC Buffer 一个color buffer的CRC buffer。一些函数,例如gpu的回调函数可能会引起这个channel的内存增加

2.3.1 MEMTRACK_TYPE_GRAPHICS

MEMTRACK_TYPE_GRAPHICS对应EGL mtrack,获取的是gralloc内存使用情况。这些数据储存在/sys/kernel/debug/ion/clients/目录的节点下(samsung)。

首先说明,graphic memory由进程触发分配,但是不会映射到进程的地址空间。
但是计算时,这部分内存可能会计算到应用的内存中。

以samsung平台为例:
对于没有TextureView和SurfaceView的应用,这个数值的大小应该是系统默认配置的Buffer数量*单个buffer的内存大小.目前系统默认BufferQueue中Buffer数量是3,那么EGL mtrack = 3 * 单个buffer的内存大小

还是以com.meizu.safe应用为例,当应用在前台时,我们查看其数据:

m17:/ # cat /sys/kernel/debug/ion/clients/32506-0                                                                                                                                     
          buffer             task  pid           thread  tid       size  # procs      flag
------------------------------------------------------------------------------------------
ffffffc00e70d880   surfaceflinger 1069    Binder:1069_4 1241    4153344        1        40
ffffffc02e16b800   surfaceflinger 1069    Binder:1069_4 1241    4153344        1        40
ffffffc06baa3100   surfaceflinger 1069    Binder:1069_2 1075    4153344        1        40
------------------------------------------------------------------------------------------
       heap_name:    size_in_bytes size_in_bytes(pss)
ion_noncontig_he:         12460032           12460032

其中ion_noncontig_he代表这个应用由gralloc分配的内存总和。

这里有一个要注意的点,按home键让应用退到后台时,ion_noncontig_he的值就为0。这是一个优化。


看完单个应用,我们再看一下机器整体的数据:
清空多任务,解锁进入桌面:

(1)adb shell dumpsys meminfo查看总共的EGL mtrack数值。

Android Memory Tracker原理分析_第2张图片

total = 18380K

(2)adb shell dumpsys meminfo surfaceflinger查看SurfaceFlinger的值

Android Memory Tracker原理分析_第3张图片

cat对应节点:

Android Memory Tracker原理分析_第4张图片

SurfaceFlinger没有EGL mtrack这项统计
虽然app对应的BufferQueue的GraphicBuffer都是由SurfaceFlinger通过gralloc申请的,但是在samsung平台上,EGL mtrack这部分数据并不算在SurfaceFlinger进程。

(3)分别查看system_server、launcher、systemui、recent的数据

Android Memory Tracker原理分析_第5张图片
Android Memory Tracker原理分析_第6张图片
Android Memory Tracker原理分析_第7张图片
Android Memory Tracker原理分析_第8张图片

PkgName EGL mtrack
system_server 4224
com.android.systemui 1988
com.meizu.flyme.launcher 12168
com.android.systemui:recents 0
total 18380

各个应用EGL mtrack数据加起来正好等于总和。

你可能感兴趣的:(Android图形框架)