dumpsys meminfo 含义

简单的查看内存信息可以使用命令:adb shell dumpsys meminfo

其入口:

android/frameworks/native/cmds/dumpsys/main.cpp

int main(int argc, char* const argv[]) {
    signal(SIGPIPE, SIG_IGN);
    sp sm = defaultServiceManager();
    fflush(stdout);
    if (sm == nullptr) {
        ALOGE("Unable to get default service manager!");
        aerr << "dumpsys: Unable to get default service manager!" << endl;
        return 20;
    }

    Dumpsys dumpsys(sm.get());
    return dumpsys.main(argc, argv);
}

通过解析参数,会调用对应servicemanager中注册的服务meminfo 的dump接口

android/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public void setSystemProcess() {
    ServiceManager.addService("meminfo", new MemBinder(this));
}

所以执行adb shell dumpsys meminfo 后最终会调用ActivityManagerService如下dump接口:

    static class MemBinder extends Binder {
        ActivityManagerService mActivityManagerService;
        MemBinder(ActivityManagerService activityManagerService) {
            mActivityManagerService = activityManagerService;
        }

        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpAndUsageStatsPermission(mActivityManagerService.mContext,
                    "meminfo", pw)) return;
            mActivityManagerService.dumpApplicationMemoryUsage(fd, pw, "  ", args, false, null);
        }
    }

dump出的信息类似以下(有精简)

Applications Memory Usage (in Kilobytes):
Uptime: 14442 Realtime: 14442

Total PSS by process:
     87,694K: system (pid 1648)
     62,996K: com.android.systemui (pid 1786)
     58,326K: com.google.android.apps.nexuslauncher (pid 2297 / activities)
     47,529K: com.google.android.googlequicksearchbox:search (pid 2367)
     46,386K: com.google.android.apps.maps (pid 2655)
     38,446K: com.google.android.inputmethod.latin (pid 1771)
     36,308K: com.google.android.gms.persistent (pid 2222)
     22,993K: com.android.phone (pid 1897)
     22,085K: zygote (pid 1521)
     21,734K: com.google.android.gms (pid 2594)
     21,199K: com.google.android.apps.photos (pid 2878)
     15,911K: com.google.android.apps.messaging:rcs (pid 2849)
     14,825K: com.google.android.apps.messaging (pid 2786)
     11,901K: com.google.android.dialer (pid 2134)
     11,842K: com.android.settings (pid 1928)
     11,403K: android.process.acore (pid 2449)
     11,009K: webview_zygote32 (pid 1818)
     ......
Total PSS by OOM adjustment:
    181,467K: Native
         22,085K: zygote (pid 1521)
         21,199K: com.google.android.apps.photos (pid 2878)
         15,911K: com.google.android.apps.messaging:rcs (pid 2849)
         11,009K: webview_zygote32 (pid 1818)
          7,350K: media.codec (pid 1534)
          6,036K: zygote (pid 2927)
          5,862K: audioserver (pid 1522)
          5,359K: rild (pid 1535)
          5,236K: wpa_supplicant (pid 1893)
          5,135K: mediaserver (pid 1530)
          4,379K: surfaceflinger (pid 1439)
          ......
     87,694K: System
         87,694K: system (pid 1648)
     85,989K: Persistent
         62,996K: com.android.systemui (pid 1786)
         22,993K: com.android.phone (pid 1897)
    142,163K: Foreground
         58,326K: com.google.android.apps.nexuslauncher (pid 2297 / activities)
         47,529K: com.google.android.googlequicksearchbox:search (pid 2367)
         36,308K: com.google.android.gms.persistent (pid 2222)
     20,794K: Visible
         10,085K: com.google.android.googlequicksearchbox:interactor (pid 2240)
          6,223K: com.google.process.gservices (pid 2324)
          4,486K: com.android.printspooler (pid 2398)
     38,446K: Perceptible
         38,446K: com.google.android.inputmethod.latin (pid 1771)
     53,109K: Previous
         21,734K: com.google.android.gms (pid 2594)
         11,403K: android.process.acore (pid 2449)
          9,451K: android.process.media (pid 2217)
          5,795K: com.google.process.gapps (pid 2507)
          4,726K: com.google.android.partnersetup (pid 2533)
    118,227K: Cached
         46,386K: com.google.android.apps.maps (pid 2655)
         14,825K: com.google.android.apps.messaging (pid 2786)
         11,901K: com.google.android.dialer (pid 2134)
         11,842K: com.android.settings (pid 1928)
          8,478K: com.google.android.deskclock (pid 2057)
          6,047K: com.android.contacts (pid 2551)
          5,523K: com.android.cellbroadcastreceiver (pid 2112)
          5,187K: com.android.providers.calendar (pid 2616)
          4,208K: com.android.managedprovisioning (pid 2579)
          3,830K: com.android.keychain (pid 2427)

Total PSS by category:
    204,398K: .dex mmap
    109,618K: .so mmap
    105,009K: Native
     85,917K: .apk mmap
     57,481K: Dalvik
     39,615K: .oat mmap
     32,382K: .art mmap
     24,693K: Dalvik Other
     21,536K: Unknown
     19,962K: Other mmap
     14,090K: .ttf mmap
     11,148K: Stack
      1,378K: Other dev
        516K: Ashmem
        140K: .jar mmap
          6K: Cursor
          0K: Gfx dev
          0K: EGL mtrack
          0K: GL mtrack
          0K: Other mtrack

Total RAM: 1,530,604K (status normal)
 Free RAM:   775,291K (  118,227K cached pss +   139,608K cached kernel +   517,456K free)
 Used RAM:   690,302K (  609,662K used pss +    80,640K kernel)
 Lost RAM:    65,011K
   Tuning: 192 (large 192), oom   184,320K, restore limit    61,440K (high-end-gfx)

Uptime: 表示启动到现在的时长,不包含休眠的时间,单位毫秒(ms)
Realtime: 表示启动到现在的时长,包含休眠的时间,单位毫秒(ms)
PSS:Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存),比如2个进程使用10KB的共享库,那么每个进程算5KB内存占用到PSS中。
Total PSS by process
这个标签下面的就是按照以PPS方式统计的,进程使用内存按多到少排列出来。
Total PSS by OOM adjustment:
这个下面是按OOM adj值排列的,就是lowmem kill时的优先级,从高到低排列
依次对应如下adj值,具体含义见注释:

android/frameworks/base/services/core/java/com/android/server/am/ProcessList.java

    // Adjustment used in certain places where we don't know it yet.
    // (Generally this is something that is going to be cached, but we
    // don't know the exact value in the cached range to assign yet.)
    static final int UNKNOWN_ADJ = 1001;

    // This is a process only hosting activities that are not visible,
    // so it can be killed without any disruption.
    static final int CACHED_APP_MAX_ADJ = 906;
    static final int CACHED_APP_MIN_ADJ = 900;

    // The B list of SERVICE_ADJ -- these are the old and decrepit
    // services that aren't as shiny and interesting as the ones in the A list.
    static final int SERVICE_B_ADJ = 800;

    // This is the process of the previous application that the user was in.
    // This process is kept above other things, because it is very common to
    // switch back to the previous app.  This is important both for recent
    // task switch (toggling between the two top recent apps) as well as normal
    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
    // and then pressing back to return to e-mail.
    static final int PREVIOUS_APP_ADJ = 700;

    // This is a process holding the home application -- we want to try
    // avoiding killing it, even if it would normally be in the background,
    // because the user interacts with it so much.
    static final int HOME_APP_ADJ = 600;

    // This is a process holding an application service -- killing it will not
    // have much of an impact as far as the user is concerned.
    static final int SERVICE_ADJ = 500;

    // This is a process with a heavy-weight application.  It is in the
    // background, but we want to try to avoid killing it.  Value set in
    // system/rootdir/init.rc on startup.
    static final int HEAVY_WEIGHT_APP_ADJ = 400;

    // This is a process currently hosting a backup operation.  Killing it
    // is not entirely fatal but is generally a bad idea.
    static final int BACKUP_APP_ADJ = 300;

    // This is a process only hosting components that are perceptible to the
    // user, and we really want to avoid killing them, but they are not
    // immediately visible. An example is background music playback.
    static final int PERCEPTIBLE_APP_ADJ = 200;

    // This is a process only hosting activities that are visible to the
    // user, so we'd prefer they don't disappear.
    static final int VISIBLE_APP_ADJ = 100;

    // This is the process running the current foreground app.  We'd really
    // rather not kill it!
    static final int FOREGROUND_APP_ADJ = 0;

    // This is a process that the system or a persistent process has bound to,
    // and indicated it is important.
    static final int PERSISTENT_SERVICE_ADJ = -700;

    // This is a system persistent process, such as telephony.  Definitely
    // don't want to kill it, but doing so is not completely fatal.
    static final int PERSISTENT_PROC_ADJ = -800;

    // The system process runs at the default adjustment.
    static final int SYSTEM_ADJ = -900;

    // Special code for native processes that are not being managed by the system (so
    // don't have an oom adj assigned by the system).
    static final int NATIVE_ADJ = -1000;

android/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    static final int[] DUMP_MEM_OOM_ADJ = new int[] {
            ProcessList.NATIVE_ADJ,
            ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ,
            ProcessList.PERSISTENT_SERVICE_ADJ, ProcessList.FOREGROUND_APP_ADJ,
            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
            ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
            ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
            ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MIN_ADJ
    };
    static final String[] DUMP_MEM_OOM_LABEL = new String[] {
            "Native",
            "System", "Persistent", "Persistent Service", "Foreground",
            "Visible", "Perceptible",
            "Heavy Weight", "Backup",
            "A Services", "Home",
            "Previous", "B Services", "Cached"
    };

其中Cached标签下的进程是随时可以回收内存的缓存进程,所以该部分内存在后面会统计到Free RAM字段中

Total RAM: 1,530,604K (status normal)
 Free RAM:   775,291K (  118,227K cached pss +   139,608K cached kernel +   517,456K free)
 Used RAM:   690,302K (  609,662K used pss +    80,640K kernel)
 Lost RAM:    65,011K
   Tuning: 192 (large 192), oom   184,320K, restore limit    61,440K (high-end-gfx)

Total PSS by category:
该标签下统计系统中所有进程每个类别占用内存的总和,具体每个的含义后面按app来解释。

用adb shell dumpsys meminfo 命令来获取单个进程对应的内存信息:

** MEMINFO in pid 5304 [personal.jayhou.meminfodemo] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2737     2668        0        0     9728     8103     1624
  Dalvik Heap      635      576        0        0     2736     1200     1536
 Dalvik Other      428      428        0        0
        Stack      252      252        0        0
       Ashmem        5        0        0        0
    Other dev       14        0       12        0
     .so mmap     1601      120        0        0
    .apk mmap      564        0        0        0
    .ttf mmap       59        0        0        0
    .dex mmap     3987        4     2228        0
    .oat mmap      306        0        0        0
    .art mmap     4131     3800       88        0
   Other mmap       13        4        0        0
      Unknown      323      288        0        0
        TOTAL    15055     8140     2328        0    12464     9303     3160

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     4464
         Native Heap:     2668
                Code:     2352
               Stack:      252
            Graphics:        0
       Private Other:      732
              System:     4587

               TOTAL:    15055       TOTAL SWAP PSS:        0

 Objects
               Views:       17         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        2        AssetManagers:        3
       Local Binders:        9        Proxy Binders:       15
       Parcel memory:        3         Parcel count:       12
    Death Recipients:        0      OpenSSL Sockets:        0
            WebViews:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

这个信息是在app进程中打印出来的,最终该命令会执行到对应进程的如下接口:

android/frameworks/base/core/java/android/app/ActivityThread.java

        @Override
        public void dumpMemInfo(ParcelFileDescriptor pfd, Debug.MemoryInfo mem, boolean checkin,
                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
                boolean dumpUnreachable, String[] args) {
            FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
            PrintWriter pw = new FastPrintWriter(fout);
            try {
                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
            } finally {
                pw.flush();
                IoUtils.closeQuietly(pfd);
            }
        }

其中
Native Heap是指c 中malloc出来的堆空间
Dalvik Heap是指java中new出来的java堆空间

                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2737     2668        0        0     9728     8103     1624
  Dalvik Heap      635      576        0        0     2736     1200     1536

这里可以看到Native Heap Pss Total列是2737 也就是native代码中分配了2737KB的空间被占用 Heap Size列是9728,是指Native堆最大是这么多KB,后面还有Heap Alloc列是8103,这里是指在虚拟地址中分配了这么多空间,Dalvik Heap同理是指java中占用的空间,这里就奇怪了,Pss Total和Heap Allock为啥不一样呢?
用Demo来试验下

public class MainActivity extends AppCompatActivity {
    private long[] m_8MB;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        m_8MB = new long[1024*1024];
        for(int i = 0; i < 1024*1024/2; i++) {
            m_8MB[i] = 0l;
        }
    }
}

如果没有for循环,只new long数组,不赋值,则:

** MEMINFO in pid 6652 [personal.jayhou.meminfodemo] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2678     2608        0        0     8704     7725      978
  Dalvik Heap      587      528        0        0    15534     9390     6144

Dalvik Heap的HeapSize调整为了15MB左右,HeapAlloc增加了8MB,正好是new long数组占用的空间,但是注意Pss Total并没有受到影响。
如果加上for循环给long数组一半的元素赋值:

** MEMINFO in pid 7099 [personal.jayhou.meminfodemo] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     2658     2584        0        0     8704     7720      983
  Dalvik Heap     4687     4628        0        0    15534     9390     6144

可以看到Dalvik Heap下的Pss Total增加了4MB 其他没变。
所以Pss Total是指占用了真实的物理内存的空间,而Heap Alloc只是占用的虚拟内存的空间。是分配了空间,没有使用的那部分内存。

虚拟内存:进程空间内的虚拟内存地址,理论上32位cpu一个进程有4GB的虚拟内存可以使用。
物理内存:就是真正写的到内存条上的,真实地址对进程不可见,由操作系统把虚拟内存地址映射到物理内存地址。

其他部分:

 Dalvik Other      428      428        0        0
        Stack      252      252        0        0
       Ashmem        5        0        0        0
    Other dev       14        0       12        0
     .so mmap     1601      120        0        0
    .apk mmap      564        0        0        0
    .ttf mmap       59        0        0        0
    .dex mmap     3987        4     2228        0
    .oat mmap      306        0        0        0
    .art mmap     4131     3800       88        0
   Other mmap       13        4        0        0
      Unknown      323      288        0        0

上面这部分顾名思义 Stack是指运行中栈空间的使用(函数调用,局部变量等),Ashmem是匿名内存占用的空间,各种mmap是对应类型文件加载部分占用内存(可以部分加载也叫映射到内存)

要查看详细的内存占用,可以查看:

adb shell cat /proc//smaps
例如刚才的进程7099实际使用的4MB内存:

cd3ff000-cdc00000 rw-p 00000000 00:01 105348                             /dev/ashmem/dalvik-large object space allocation (deleted)
Size:               8196 kB
Rss:                4100 kB
Pss:                4100 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:      4100 kB
Referenced:         4100 kB
Anonymous:          4100 kB
AnonHugePages:         0 kB
Swap:                  0 kB
SwapPss:               0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB

Size:指的就是分配了多少虚拟内存
Rss、Pss指的是实际物理内存使用的大小,由于这个内存段是纯new出来的,没有共享库,所以这两个值是一样的。由于只给4MB的数组赋值,操作系统只给分配了4MB的真实物理内存。

把/proc//smaps 所有数据段中Pss部分加起来,和上面所有类型的Pss加起的TOTAL行的Pss Total值是一样的

        TOTAL:    15055

其他部分:

 App Summary
                       Pss(KB)
                        ------
           Java Heap:     4464
         Native Heap:     2668
                Code:     2352
               Stack:      252
            Graphics:        0
       Private Other:      732
              System:     4587

               TOTAL:    15055       TOTAL SWAP PSS:        0

 Objects
               Views:       17         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        2        AssetManagers:        3
       Local Binders:        9        Proxy Binders:       15
       Parcel memory:        3         Parcel count:       12
    Death Recipients:        0      OpenSSL Sockets:        0
            WebViews:        0

 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

App Summary部分换了一种方式统计Pss内存占用,其Total值和上面部分一致。具体含义可以参考如下代码:

android/frameworks/base/core/java/android/app/ActivityThread.java

        printRow(pw, ONE_COUNT_COLUMN,
            "Java Heap:", memInfo.getSummaryJavaHeap());
        printRow(pw, ONE_COUNT_COLUMN,
            "Native Heap:", memInfo.getSummaryNativeHeap());
        printRow(pw, ONE_COUNT_COLUMN,
            "Code:", memInfo.getSummaryCode());
        printRow(pw, ONE_COUNT_COLUMN,
            "Stack:", memInfo.getSummaryStack());
        printRow(pw, ONE_COUNT_COLUMN,
            "Graphics:", memInfo.getSummaryGraphics());
        printRow(pw, ONE_COUNT_COLUMN,
            "Private Other:", memInfo.getSummaryPrivateOther());
        printRow(pw, ONE_COUNT_COLUMN,
            "System:", memInfo.getSummarySystem());

android/frameworks/base/core/java/android/os/Debug.java

        /**
         * Pss of Java Heap bytes in KB due to the application.
         * Notes:
         *  * OTHER_ART is the boot image. Anything private here is blamed on
         *    the application, not the system.
         *  * dalvikPrivateDirty includes private zygote, which means the
         *    application dirtied something allocated by the zygote. We blame
         *    the application for that memory, not the system.
         *  * Does not include OTHER_DALVIK_OTHER, which is considered VM
         *    Overhead and lumped into Private Other.
         *  * We don't include dalvikPrivateClean, because there should be no
         *    such thing as private clean for the Java Heap.
         * @hide
         */
        public int getSummaryJavaHeap() {
            return dalvikPrivateDirty + getOtherPrivate(OTHER_ART);
        }

        /**
         * Pss of Native Heap bytes in KB due to the application.
         * Notes:
         *  * Includes private dirty malloc space.
         *  * We don't include nativePrivateClean, because there should be no
         *    such thing as private clean for the Native Heap.
         * @hide
         */
        public int getSummaryNativeHeap() {
            return nativePrivateDirty;
        }

        /**
         * Pss of code and other static resource bytes in KB due to
         * the application.
         * @hide
         */
        public int getSummaryCode() {
            return getOtherPrivate(OTHER_SO)
              + getOtherPrivate(OTHER_JAR)
              + getOtherPrivate(OTHER_APK)
              + getOtherPrivate(OTHER_TTF)
              + getOtherPrivate(OTHER_DEX)
              + getOtherPrivate(OTHER_OAT);
        }

        /**
         * Pss in KB of the stack due to the application.
         * Notes:
         *  * Includes private dirty stack, which includes both Java and Native
         *    stack.
         *  * Does not include private clean stack, because there should be no
         *    such thing as private clean for the stack.
         * @hide
         */
        public int getSummaryStack() {
            return getOtherPrivateDirty(OTHER_STACK);
        }

        /**
         * Pss in KB of graphics due to the application.
         * Notes:
         *  * Includes private Gfx, EGL, and GL.
         *  * Warning: These numbers can be misreported by the graphics drivers.
         *  * We don't include shared graphics. It may make sense to, because
         *    shared graphics are likely buffers due to the application
         *    anyway, but it's simpler to implement to just group all shared
         *    memory into the System category.
         * @hide
         */
        public int getSummaryGraphics() {
            return getOtherPrivate(OTHER_GL_DEV)
              + getOtherPrivate(OTHER_GRAPHICS)
              + getOtherPrivate(OTHER_GL);
        }

        /**
         * Pss in KB due to the application that haven't otherwise been
         * accounted for.
         * @hide
         */
        public int getSummaryPrivateOther() {
            return getTotalPrivateClean()
              + getTotalPrivateDirty()
              - getSummaryJavaHeap()
              - getSummaryNativeHeap()
              - getSummaryCode()
              - getSummaryStack()
              - getSummaryGraphics();
        }

        /**
         * Pss in KB due to the system.
         * Notes:
         *  * Includes all shared memory.
         * @hide
         */
        public int getSummarySystem() {
            return getTotalPss()
              - getTotalPrivateClean()
              - getTotalPrivateDirty();
        }

Objects是统计App内部组件对象个数,其中Views、ViewRootImpl以及Activities个数,在Activity onDestroy后应该都会回收清零,如果onDestroy调用后这几个对象个数没有清零,就可能发生了内存泄漏。

你可能感兴趣的:(dumpsys meminfo 含义)