Android 4.4 meminfo Implementation Analysis

Source: Internet
Author: User
Tags strcmp

Android provides a small tool named meminfo to help the application analyze its memory usage. In addition, the memtrack HAL module is added in 4.4. The SoC vendor implements the memtrack module, let meminfo Get Some GPU-related memory allocation conditions. Understanding the implementation of meminfo is helpful for us to learn more about the memory usage of the application. The purpose of this article is to analyze the internal implementation source code of Android 4.4 meminfo, so that developers can better understand the memory usage of their applications.

Enter the command "adb shell dumpsys meminfo YOUR-PACKAGE-NAME" on the console, and you can see similar results:

** MEMINFO in pid 14120 [com.UCMobile.test] **                   Pss  Private  Private  Swapped     Heap     Heap     Heap                 Total    Dirty    Clean    Dirty     Size    Alloc     Free                ------   ------   ------   ------   ------   ------   ------  Native Heap   187886   187872        0        0   325232   174093    38594  Dalvik Heap    24801    24444        0        0    41476    35899     5577 Dalvik Other      700      700        0        0                                   Stack      508      508        0        0                               Other dev    33564    32600        4        0                                .so mmap     9019     1244     7268        0                               .apk mmap      101        0       16        0                               .ttf mmap     1330        0      696        0                               .dex mmap     2248        0     2248        0                               code mmap      985        0      188        0                              image mmap     1182      908       12        0                              Other mmap      130        4      108        0                                Graphics    25504    25504        0        0                                      GL     2196     2196        0        0                                 Unknown    32476    32476        0        0                                   TOTAL   322630   308456    10540        0   366708   209992    44171

The actual call code entry is in android. OS. Debug. java and the corresponding CPP file android_ OS _Debug.cpp. The getMeminfo method of Debug. java actually calls android_ OS _Debug.cpp's android_ OS _Debug_getDirtyPagesPid method.

static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,        jint pid, jobject object){    stats_t stats[_NUM_HEAP];    memset(&stats, 0, sizeof(stats));    load_maps(pid, stats);    struct graphics_memory_pss graphics_mem;    if (read_memtrack_memory(pid, &graphics_mem) == 0) {        ...    }    ...}static void load_maps(int pid, stats_t* stats){    char tmp[128];    FILE *fp;    sprintf(tmp, "/proc/%d/smaps", pid);    fp = fopen(tmp, "r");    if (fp == 0) return;    read_mapinfo(fp, stats);    fclose(fp);}

From the code above, we can see that the android_ OS _Debug_getDirtyPagesPid method first calls the load_maps method, and the load_maps method is easy to do. It opens the/proc/PID/smaps Virtual File and reads the information in it, on a ROOT device, we can directly print the information of this virtual file on the console through "adb shell cat/proce/PID/smaps.

80ff5000-810f2000 rw-p 00000000 00:00 0          [stack:12211]Size:               1012 kBRss:                   4 kBPss:                   4 kB...81100000-811a4000 rw-s 000f4000 00:0b 6285       /dev/kgsl-3d0Size:                656 kBRss:                 652 kBPss:                 352 kB...811d1000-811e0000 rw-p 00000000 00:00 0          [anon:libc_malloc]Size:                 60 kBRss:                  60 kBPss:                  60 kB...Name:           [anon:libc_malloc]

Shows the information output by "adb shell cat/proce/PID/smaps". It is actually the memory allocation table of the application's userspace address space, recording the address of each memory allocated by the application, class, size, and other information. The load_maps method calls the read_mapinfo method to read the allocation information of each piece of memory from this table, and accumulate the classes to obtain the Native Heap, memory usage of Dalvik Heap and other categories.

However, some memory blocks in all the memory used by the application are not mapped to the userspace address space of the process (mainly the memory used by the GPU ), the memory block information cannot be found in smaps. Therefore, a memtrack HAL module is added in Android 4.4 to be implemented by the SoC vendor. If the SoC vendor implements the memtrack module, meminfo can call libmemtrack to obtain GPU-related memory usage information. Therefore, we can see that the android_ OS _Debug_getDirtyPagesPid method reads the memory usage information of Graphics and GL by calling the read_memtrack_memory method.

/* * Uses libmemtrack to retrieve graphics memory that the process is using. * Any graphics memory reported in /proc/pid/smaps is not included here. */static int read_memtrack_memory(struct memtrack_proc* p, int pid,        struct graphics_memory_pss* graphics_mem){    int err = memtrack_proc_get(p, pid);    ...    ssize_t pss = memtrack_proc_graphics_pss(p);    ...    graphics_mem->graphics = pss / 1024;    pss = memtrack_proc_gl_pss(p);    ...    graphics_mem->gl = pss / 1024;    pss = memtrack_proc_other_pss(p);    ...    graphics_mem->other = pss / 1024;    return 0;}

Shows the implementation of the read_memtrack_memory method. It reads information about Graphics, GL, and Other memory, and defines the three categories in hardware/memtrack. h.

/* * The Memory Tracker HAL is designed to return information about device-specific * memory usage.  The primary goal is to be able to track memory that is not * trackable in any other way, for example texture memory that is allocated by * a process, but not mapped in to that process' address space. * A secondary goal is to be able to categorize memory used by a process into * GL, graphics, etc.  All memory sizes should be in real memory usage, * accounting for stride, bit depth, rounding up to page size, etc. * * A process collecting memory statistics will call getMemory for each * combination of pid and memory type.  For each memory type that it recognizes * the HAL should fill out an array of memtrack_record structures breaking * down the statistics of that memory type as much as possible.  For example, * getMemory(, MEMTRACK_TYPE_GL) might return: * { { 4096,  ACCOUNTED | PRIVATE | SYSTEM }, *   { 40960, UNACCOUNTED | PRIVATE | SYSTEM }, *   { 8192,  ACCOUNTED | PRIVATE | DEDICATED }, *   { 8192,  UNACCOUNTED | PRIVATE | DEDICATED } } * If the HAL could not differentiate between SYSTEM and DEDICATED memory, it * could return: * { { 12288,  ACCOUNTED | PRIVATE }, *   { 49152,  UNACCOUNTED | PRIVATE } } * * Memory should not overlap between types.  For example, a graphics buffer * that has been mapped into the GPU as a surface should show up when * MEMTRACK_TYPE_GRAPHICS is requested, and not when MEMTRACK_TYPE_GL * is requested. */enum memtrack_type {    MEMTRACK_TYPE_OTHER = 0,    MEMTRACK_TYPE_GL = 1,    MEMTRACK_TYPE_GRAPHICS = 2,    MEMTRACK_TYPE_MULTIMEDIA = 3,    MEMTRACK_TYPE_CAMERA = 4,    MEMTRACK_NUM_TYPES,};

Graphics corresponds to MEMTRACK_TYPE_GRAPHICS, GL corresponds to MEMTRACK_TYPE_GL, and Other is actually the sum of MEMTRACK_TYPE_OTHER, MEMTRACK_TYPE_MULTIMEDIA, MEMTRACK_TYPE_CAMERA. Memtrack is implemented by SoC vendors. In the AOSP source code, we can find the Qualcomm implementation source code in msm8974/libmemtrack/kgsl. c.

int kgsl_memtrack_get_memory(pid_t pid, enum memtrack_type type,                             struct memtrack_record *records,                             size_t *num_records){    ...    sprintf(tmp, "/d/kgsl/proc/%d/mem", pid);    fp = fopen(tmp, "r");    ...    if (type == MEMTRACK_TYPE_GL) {        sprintf(tmp, "/proc/%d/smaps", pid);        smaps_fp = fopen(tmp, "r");        ...    }    while (1) {        unsigned long uaddr;        unsigned long size;        char line_type[7];        int ret;        if (fgets(line, sizeof(line), fp) == NULL) {            break;        }        /* Format:         *  gpuaddr useraddr     size    id flags       type            usage sglen         * 545ba000 545ba000     4096     1 ----p     gpumem      arraybuffer     1         */        ret = sscanf(line, "%*x %lx %lu %*d %*s %6s %*s %*d\n",                     &uaddr, &size, line_type);        if (ret != 3) {            continue;        }        if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {            bool accounted = false;            /*             * We need to cross reference the user address against smaps,             *  luckily both are sorted.             */            while (smaps_addr <= uaddr) {                unsigned long start;                unsigned long end;                unsigned long smaps_size;                if (fgets(line, sizeof(line), smaps_fp) == NULL) {                    break;                }                if (sscanf(line, "%8lx-%8lx", &start, &end) == 2) {                    smaps_addr = start;                    continue;                }                if (smaps_addr != uaddr) {                    continue;                }                if (sscanf(line, "Rss: %lu kB", &smaps_size) == 1) {                    if (smaps_size) {                        accounted = true;                        accounted_size += size;                        break;                    }                }            }            if (!accounted) {                unaccounted_size += size;            }        } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {            unaccounted_size += size;        }    }    ...}

Kgsl_memtrack_get_memory is the specific implementation of the getMemory method of memtrack. We can see that it actually reads the information of an internal GPU Memory Allocation Table (Virtual File/d/kgsl/proc/PID/mem ), on the ROOT device, we can print the information of this memory allocation table to the console through "adb shell cat/d/kgsl/proc/PID/mem", as shown in:

 gpuaddr useraddr     size    id flags       type            usage sglen7565e000 00000000     4096     1 ----p     gpumem      arraybuffer     1756bc000 00000000    65536     2 -r--p     gpumem          command    16756cd000 00000000    65536     3 -r--p     gpumem          command    16756de000 00000000    65536     4 -r--p     gpumem          command    16756fb000 00000000     4096     5 ----p     gpumem               gl     175fe2000 00000000   262144     6 ----p     gpumem               gl    6476023000 00000000     8192     7 ----p     gpumem               gl     276026000 00000000     8192     8 ----p     gpumem               gl     276029000 00000000     4096     9 ----p     gpumem          texture     1...94d71000 00000000   131072   362 ----p     gpumem  vertexarraybuff    3294da0000 00000000   667648   176 --l-p     gpumem          texture   16394e44000 00000000   131072   363 ----p     gpumem           any(0)    3294e65000 00000000   131072   364 ----p     gpumem           any(0)    32c0000000 00000000 17268736    31 --L--        ion        egl_image  4216c1100000 00000000  8257536    36 --L--        ion      egl_surface    21c1900000 00000000  8257536   164 --L--        ion      egl_surface    21c2100000 00000000  8257536   175 --L--        ion      egl_surface    21

The memory blocks of the ion type (memory allocated by the ION memory distributor) are counted into the Graphics category. We can see three egl_surface blocks, they correspond to the three buffers in the window used by the application, and an egl_image is not clear for the time being (the address and ID number of this 17M egl_image are the same in different processes, so I guess it's actually the Assert Atlas that Android shares between different apps. Android 4.4 starts to splice the image resources of the system into a large texture, then use GraphicBuffer + EGLImage to share among different applications. These are automatically allocated by Android after the application is started. Memory blocks of the gpumem type are counted into the GL category, including texture, various shader, and vertex buffer in the GL. In addition, because some memory blocks are mapped to userspace, some do not have mappings, the memory blocks mapped to userspace are marked as accounted to avoid repeated meminfo counts, the memory values of Graphics and GL displayed by meminfo are the sum of memory blocks not mapped to userspace.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.