美文网首页
Android Memory Tracker原理分析

Android Memory Tracker原理分析

作者: Simon_MiaoV | 来源:发表于2020-08-05 14:22 被阅读0次

    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的流程

    这里写图片描述

    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数值。

    total = 18380K

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

    cat对应节点:

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

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



    | 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 Memory Tracker原理分析

          本文链接:https://www.haomeiwen.com/subject/tenerktx.html