文章出处:android 查看内存使用情况_私房菜-CSDN博客

请转载的朋友标明出处~~

源码基于:Android R

  1. cat /proc/meminfo

     MemTotal: 所有可用RAM大小 (即物理内存减去一些预留位和内核的二进制代码大小)
    
     MemFree: LowFree与HighFree的总和
    
     Buffers: 用来给块设备做的缓冲大小(只记录文件系统的metadata以及 tracking in-flight pages,就是说 buffers是用来存储,目录里面有什么内容,权限等等。)
    
     Cached: 用来给文件做缓冲大小(直接用来记忆我们打开的文件). 它不包括SwapCached
    
     SwapCached: 已经被交换出来的内存,但仍然被存放在swapfile中。用来在需要的时候很快的被替换而不需要再次打开I/O端口。
    
     Active: 最近经常被使用的内存,除非非常必要否则不会被移作他用.
    
     Inactive: 最近不经常被使用的内存,非常用可能被用于其他途径.
    
     HighTotal:
     HighFree: 高位内存是指所有在860MB以上的内存空间,该区域主要用于用户空间的程序或者是缓存页面。内核必须使用不同的手法使用该段内存,因此它比低位内存要慢一些。
    
     LowTotal:
     LowFree: 低位可以达到高位内存一样的作用,而且它还能够被内核用来记录一些自己的数据结构。
                    Among many other things, it is where everything from the Slab is
                    allocated.  Bad things happen when you're out of lowmem.
     SwapTotal: 交换空间的总和
     SwapFree: 从RAM中被替换出暂时存在磁盘上的空间大小
     Dirty: 等待被写回到磁盘的内存大小。
     Writeback: 正在被写回到磁盘的内存大小。
     Mapped: 影射文件的大小。
     Slab: 内核数据结构缓存
     VmallocTotal: vmalloc内存大小
     VmallocUsed: 已经被使用的虚拟内存大小。
     VmallocChunk: largest contigious block of vmalloc area which is free
     CommitLimit:
     Committed_AS:
    
  2. dumpsys meminfo

更多关于dumpsys的使用信息,可以查看:android 中的dumpsys

可以dump的这些service都是在ServiceManager里面添加上的,例如meminfo是在:frameworks/base/services/java/com/android/server/am/ActivityManagerService.java的函数setSystemProcess添加的:

    public void setSystemProcess() {
        try {
            ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
                    DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
            ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
            ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
                    DUMP_FLAG_PRIORITY_HIGH);
            ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
            ServiceManager.addService("dbinfo", new DbBinder(this));
            if (MONITOR_CPU_USAGE) {
                ServiceManager.addService("cpuinfo", new CpuBinder(this),
                        /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
            }
            ServiceManager.addService("permission", new PermissionController(this));
            ServiceManager.addService("processinfo", new ProcessInfoService(this));
            ServiceManager.addService("cacheinfo", new CacheBinder(this));
 
            ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                    "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY);
            mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
 
            ...

来看一下MemBinder:

            @Override
            public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
                mActivityManagerService.dumpApplicationMemoryUsage(
                        fd, pw, "  ", args, false, null, asProto);
            }

最终调用的是:

mActivityManagerService.dumpApplicationMemoryUsage

具体的source code这里暂不作分析了。

2.1 dumpsys meminfo -h

    } else if ("-h".equals(opt)) {
        pw.println("meminfo dump options: [-a] [-d] [-c] [-s] [--oom] [process]");
        pw.println("  -a: include all available information for each process.");
        pw.println("  -d: include dalvik details.");
        pw.println("  -c: dump in a compact machine-parseable representation.");
        pw.println("  -s: dump only summary of application memory usage.");
        pw.println("  -S: dump also SwapPss.");
        pw.println("  --oom: only show processes organized by oom adj.");
        pw.println("  --local: only collect details locally, don't call process.");
        pw.println("  --package: interpret process arg as package, dumping all");
        pw.println("             processes that have loaded that package.");
        pw.println("  --checkin: dump data for a checkin");
        pw.println("  --proto: dump data to proto");
        pw.println("If [process] is specified it can be the name or ");
        pw.println("pid of a specific process to dump.");
        return;
    }

2.2 单个进程的meminfo

shift:/ # dumpsys meminfo com.android.launcher3
Applications Memory Usage (in Kilobytes):
Uptime: 4443605 Realtime: 4443605
 
** MEMINFO in pid 1834 [com.android.launcher3] **
                   Pss  Private  Private     Swap      Rss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty    Total     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------   ------
  Native Heap    13647    13548        0        0    16152    21672    16064     1962
  Dalvik Heap     5338     5144        0        0     9496     6657     3329     3328
 Dalvik Other     1317     1192        0        0     2376
        Stack      636      636        0        0      644
       Ashmem        2        0        0        0       20
    Other dev      140        0      140        0      392
     .so mmap     7350      232       12        0    57116
    .jar mmap     2359        0       76        0    24984
    .apk mmap    22108        0    15208        0    51748
    .ttf mmap      110        0        0        0      376
    .dex mmap      348        8      336        0      432
    .oat mmap     1384        0        0        0    14560
    .art mmap     2434     1608        4        0    20496
   Other mmap      495       60       24        0     2896
      Unknown      599      588        0        0     1128
        TOTAL    58267    23016    15800        0    58267    28329    19393     5290
 
 App Summary
                       Pss(KB)                        Rss(KB)
                        ------                         ------
           Java Heap:     6756                          29992
         Native Heap:    13548                          16152
                Code:    15872                         149484
               Stack:      636                            644
            Graphics:        0                              0
       Private Other:     2004
              System:    19451
             Unknown:                                    6544
 
           TOTAL PSS:    58267            TOTAL RSS:   202816      TOTAL SWAP (KB):        0
 
 Objects
               Views:       89         ViewRootImpl:        1
         AppContexts:       10           Activities:        1
              Assets:       14        AssetManagers:        0
       Local Binders:       34        Proxy Binders:       43
       Parcel memory:       13         Parcel count:       69
    Death Recipients:        1      OpenSSL Sockets:        0
            WebViews:        0
 
 SQL
         MEMORY_USED:      682
  PAGECACHE_OVERFLOW:      292          MALLOC_SIZE:      117
 
 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       16             20         1/14/1  /data/user/0/com.android.launcher3/databases/widgetpreviews.db
         4      252             71        99/18/5  /data/user/0/com.android.launcher3/databases/app_icons.db
         4       16             57         6/17/4  /data/user/0/com.android.launcher3/databases/launcher.db

来看下其中几个主要概念:

           Java Heap:    24312  dalvik heap + .art mmap
         Native Heap:    62256
                Code:    66452    .so mmap + .jar mmap + .apk mmap + .ttf mmap + .dex mmap + .oat mmap
               Stack:       84
            Graphics:     5338    Gfx dev + EGL mtrack + GL mtrack
       Private Other:     9604  TotalPrivateClean + TotalPrivateDirty - java - native - code - stack - graphics
              System:    12900    TotalPss - TotalPrivateClean - TotalPrivateDirty

下面的解释来源于

https://developer.android.com/studio/profile/investigate-ram?hl=zh-cn

Dalvik Heap

您的应用中 Dalvik 分配占用的 RAM。Pss Total 包括所有 Zygote 分配(如上述 PSS 定义所述,通过进程之间的共享内存量来衡量)。Private Dirty 数值是仅分配到您应用的堆的实际 RAM,由您自己的分配和任何 Zygote 分配页组成,这些分配页自从 Zygote 派生应用进程以来已被修改。

Heap Alloc

是 Dalvik 和原生堆分配器为您的应用跟踪的内存量。此值大于 Pss Total 和 Private Dirty,因为您的进程从 Zygote 派生,且包含您的进程与所有其他进程共享的分配。

.so mmap 和 .dex mmap

映射的 .so(原生)和 .dex(Dalvik 或 ART)代码占用的 RAM。Pss Total 数值包括应用之间共享的平台代码;Private Clean 是您的应用自己的代码。通常情况下,实际映射的内存更大 - 此处的 RAM 仅为应用执行的代码当前所需的 RAM。不过,.so mmap 具有较大的私有脏 RAM,因为在加载到其最终地址时对原生代码进行了修改。

.oat mmap

这是代码映像占用的 RAM 量,根据多个应用通常使用的预加载类计算。此映像在所有应用之间共享,不受特定应用影响。

.art mmap

这是堆映像占用的 RAM 量,根据多个应用通常使用的预加载类计算。此映像在所有应用之间共享,不受特定应用影响。尽管 ART 映像包含 Object 实例,它仍然不会计入您的堆大小。

But as to what the difference is between "Pss", "PrivateDirty", and "SharedDirty"... well now the fun begins.
 
A lot of memory in Android (and Linux systems in general) is actually shared across multiple processes. 
So how much memory a processes uses is really not clear. Add on top of that paging out to disk (let alone swap which we don't use on 
Android) and it is even less clear.
Thus if you were to take all of the physical RAM actually mapped in to each process, and add up all of the processes, 
you would probably end up with a number much greater than the actual total RAM.
The Pss number is a metric the kernel computes that takes into account memory sharing -- basically each page of RAM in a process is 
scaled by a ratio of the number of other processes also using that page. This way you can (in theory) add up the pss across all 
processes to see the total RAM they are using, and compare pss between processes to get a rough idea of their relative weight.
The other interesting metric here is PrivateDirty, which is basically the amount of RAM inside the process that can not be paged 
to disk (it is not backed by the same data on disk), and is not shared with any other processes. Another way to look at this is the 
RAM that will become available to the system when that process goes away (and probably quickly subsumed into caches and other uses 
of it).

从这篇文章中得知:

一般的android和linux系统中很多进程会共享一些mem,所以一个进程用到的mem其实不是十分清除,

因此如果将每个进程实际占用的mem加到一起,可能会发现这个结果会远远的超过实际的总的mem。

Pss 是kernel根据共享mem计算得到的值,Pss的值是一块共享mem中一定比例的值。这样,将所有进程Pss加起来就是总的RAM值了,也可以通过进程间Pss值得到这些进程使用比重情况。

PrivateDirty,它基本上是进程内不能被分页到磁盘的内存,也不和其他进程共享。查看进程的内存用量的另一个途径,就是当进程结束时刻,系统可用内存的变化情况(也可能会很快并入高速缓冲或其他使用该内存区的进程)

 其他类型              smap 路径名称                       描述
 
Ashmem              /dev/ashmem            匿名共享内存用来提供共享内存通过分配一个多个进程
                                                         可以共享的带名称的内存块
Other dev            /dev/                         内部driver占用的在 “Other dev”                                                 
.so mmap             .so                           C 库代码占用的内存
.jar mmap            .jar                          Java 文件代码占用的内存
.apk mmap            .apk                          apk代码占用的内存
.ttf mmap            .ttf                          ttf 文件代码占用的内存
.dex mmap            .dex                          Dex 文件代码占用的内存
Other mmap                                         其他文件占用的内存 

2.3 系统meminfo 统计

Total RAM: 3,768,168K (status normal)
 Free RAM: 2,186,985K (   64,861K cached pss +   735,736K cached kernel + 1,386,388K free)
      ION:    58,408K (   53,316K mapped +      -128K unmapped +     5,220K pools)
 Used RAM: 1,440,349K (1,116,469K used pss +   323,880K kernel)
 Lost RAM:   140,822K
     ZRAM:        12K physical used for         0K in swap (2,097,148K total swap)
   Tuning: 256 (large 512), oom   640,000K, restore limit   213,333K (high-end-gfx)

2.3.1 Total RAM

pw.print(stringifyKBSize(memInfo.getTotalSizeKb()));

Total RAM 就是/proc/meminfo 中的 MemTotal
2.3.2 Free RAM

pw.print(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb()
                                       + memInfo.getFreeSizeKb()));

括号中的:

cached pss:All pss of process oom_score_adj >= 900
cached kernel:/proc/meminfo.Buffers + /proc/meminfo.KReclaimable +                                                                                         /proc/meminfo.Cached - /proc/meminfo.Mapped
free:/proc/meminfo.MemFree

2.3.3 Used RAM

pw.print(stringifyKBSize(totalPss - cachedPss + kernelUsed));

括号中的

used pss:totalPss - cachedPss
KernelUsed:/proc/meminfo.Shmem + /proc/meminfo.SlabUnreclaim + VmallocUsed + /proc/meminfo.PageTables + /proc/meminfo.KernelStack + [ionHeap]

2.3.4 Lost RAM

            final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
                    - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
                    - kernelUsed - memInfo.getZramTotalSizeKb();

Lost RAM:proc/meminfo.Memtotal - (totalPss - totalSwapPss) - /proc/meminfo.Memfree - /proc/meminfo.Cached - kernel used - zram used
2.3.5 Tuning

        pw.print("   Tuning: ");
        pw.print(ActivityManager.staticGetMemoryClass());
        pw.print(" (large ");
        pw.print(ActivityManager.staticGetLargeMemoryClass());
        pw.print("), oom ");
        pw.print(stringifySize(
                    mProcessList.getMemLevel(ProcessList.CACHED_APP_MAX_ADJ), 1024));
        pw.print(", restore limit ");
        pw.print(stringifyKBSize(mProcessList.getCachedRestoreThresholdKb()));
        if (ActivityManager.isLowRamDeviceStatic()) {
            pw.print(" (low-ram)");
        }
        if (ActivityManager.isHighEndGfx()) {
            pw.print(" (high-end-gfx)");
        }
        pw.println();

large:dalvik.vm.heapsize属性取值,单位为MB

oom:ProcessList中mOomMinFree数组最后一个元素取值

restore limit:ProcessList中mCachedRestoreLevel变量取值,将一个进程从cached 到background的最大值,一般是mOomMinFree 最后一个值的 1/3.

low-ram:是否为low ram 设备,一般通过prop ro.config.low_ram,或者当ro.debuggable 使能时prop debug.force_low_ram。

high-end-gfx:ro.config.low_ram 为false,且ro.config.avoid_gfx_accel 为false,且config config_avoidGfxAccel 的值为false。

  1. procrank

    root@h15:/ # procrank
    PID Vss Rss Pss Uss cmdline
    4034 744312K 80076K 63779K 61188K com.qiyi.video
    3887 691700K 69676K 54293K 51784K com.android.systemui
    3749 709572K 36112K 20045K 17728K system_server
    2586 55280K 15424K 10098K 8804K /system/bin/tvserver
    2594 68848K 14268K 8235K 6124K /system/bin/mediaserver
    4151 665424K 20184K 7157K 6016K android.process.acore



    2599 3512K 452K 180K 168K /system/bin/sdcard
    2595 1000K 444K 165K 152K /system/bin/installd
    2608 1500K 176K 160K 160K /sbin/adbd
    2580 1428K 148K 136K 136K /sbin/healthd
    2582 1008K 348K 118K 108K /system/bin/servicemanager
    2588 364K 96K 80K 80K /system/bin/dig
    ------ ------ ------
    236736K 207864K TOTAL

    RAM: 753344K total, 260444K free, 6788K buffers, 187252K cached, 348K shmem, 11480K slab

Android procrank (/system/xbin/procrank) 工具,能够列出进程所占用的内存使用情况。顺序为从高到低。
每个进程占用内存大小以 VSS, RSS , PSS, USS 的形式列出。
为了简化描述,内存占用以页为单位表述,而不是字节。 通常每页为 4096 字节。

VSS ( 等同于 ps 命令列出的 VSZ) 是单个进程全部可访问的地址空间。
其大小包括可能还尚未在内存中驻留的部分。比如地址空间已经被 malloc 分配,但是还没有实际写入。
对于确定单个进程实际内存使用大小, VSS 用处不大。

RSS 是单个进程实际占用的内存大小。
RSS 易被误导的原因在于, 它包括了该进程所使用的所有共享库的全部内存大小。对于单个共享库, 尽管无论多少个进程使用,
实际该共享库只会被装入内存一次。
对于单个进程的内存使用大小, RSS 不是一个精确的描述。

PSS 不同于RSS,它只是按比例包含其所使用的共享库大小。
例如, 三个进程使用同一个占用 30 内存页的共享库。 对于三个进程中的任何一个,PSS 将只包括 10 个内存页。
PSS 是一个非常有用的数字,因为系统中全部进程以整体的方式被统计, 对于系统中的整体内存使用是一个很好的描述。
如果一个进程被终止, 其PSS 中所使用的共享库大小将会重新按比例分配给剩下的仍在运行并且仍在使用该共享库的进程。
此种计算方式有轻微的误差,因为当某个进程中止的时候, PSS 没有精确的表示被返还给整个系统的内存大小。

USS 是单个进程的全部私有内存大小。亦即全部被该进程独占的内存大小。
USS 是一个非常非常有用的数字, 因为它揭示了运行一个特定进程的真实的内存增量大小。
如果进程被终止, USS 就是实际被返还给系统的内存大小。
USS 是针对某个进程开始有可疑内存泄露的情况,进行检测的最佳数字。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐