Android MEM性能数据获取

简介: 查看内存使用情况使用adb dumpsys 命令 adb shell dumpsys meminfo 其中,package_name 也可以换成程序的pid,pid可以通过 adb shell top | grep app_name 来查找,下图是滴滴主端的内存使用情况应用级内存didi@bogon  ~  adb shell dumpsys meminfo com.

查看内存使用情况
使用adb dumpsys 命令 adb shell dumpsys meminfo 其中,package_name 也可以换成程序的pid,pid可以通过 adb shell top | grep app_name 来查找,下图是滴滴主端的内存使用情况

应用级内存

didi@bogon  ~  adb shell dumpsys meminfo com.sdu.didi.psnger
Applications Memory Usage (in Kilobytes):
Uptime: 180975 Realtime: 180975
** MEMINFO in pid 7914 [com.sdu.didi.psnger] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap    32081    31972       92      294    59904    41985    17918
  Dalvik Heap    26859    26764        0      318    27257    16354    10903
 Dalvik Other     6354     6348        0        0
        Stack     1424     1424        0        0
       Ashmem     1558     1544        0        0
      Gfx dev     4942     1636        8        0
    Other dev       27        0       24        0
     .so mmap    13066      384     8904      199
    .apk mmap    19677       80    16676        0
    .ttf mmap       11        0        0        0
    .dex mmap    48628       24    37604        0
    .oat mmap    12470        0     3128        0
    .art mmap     2754     1872       44       15
   Other mmap     2227        8     1256        0
   EGL mtrack    41100    41100        0        0
    GL mtrack     6984     6984        0        0
      Unknown     5939     5924       12       99
        TOTAL   227026   126064    67748      925    87161    58339    28821
 App Summary
                       Pss(KB)
                        ------
           Java Heap:    28680
         Native Heap:    31972
                Code:    66800
               Stack:     1424
            Graphics:    49728
       Private Other:    15208
              System:    33214
               TOTAL:   227026       TOTAL SWAP PSS:      925
 Objects
               Views:      121         ViewRootImpl:        1
         AppContexts:        3           Activities:        1
              Assets:        4        AssetManagers:        3
       Local Binders:       75        Proxy Binders:       35
       Parcel memory:       37         Parcel count:      131
    Death Recipients:        1      OpenSSL Sockets:        7
 SQL
         MEMORY_USED:      945
  PAGECACHE_OVERFLOW:      263          MALLOC_SIZE:       62
 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       88            135        16/40/7  /storage/emulated/0/Android/data/com.sdu.didi.psnger/files/im/im_database_282680000258050.db
         4       28             45      171/107/4  /data/user/0/com.sdu.didi.psnger/databases/dns_record.db
         4       32             84        10/24/7  /data/user/0/com.sdu.didi.psnger/databases/ad
         4       20             37        46/22/5  /data/user/0/com.sdu.didi.psnger/databases/location_info.db
         4       24             41         5/19/2  /data/user/0/com.sdu.didi.psnger/databases/download_file.db
         4      100            149       58/44/25  /data/user/0/com.sdu.didi.psnger/databases/DIDI_DATABASE
         4       20             19         0/23/2  /data/user/0/com.sdu.didi.psnger/databases/audio_record_2
         4       12                         0/0/0    (attached) temp
         4       20             56         3/15/3  /data/user/0/com.sdu.didi.psnger/databases/audio_record_2 (1)

重点关注如下几个字段:

(1) 私有(Clean and Dirty)内存

进程独占的内存,也就是应用进程销毁时系统可以直接回收的内存容量。 通常来说,“private dirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储,因此不能做分页存储到外存(Android不支持swap)。 所有分配的Dalvik堆和本地堆都是“private dirty”内存;Dalvik堆和本地堆中和Zygote进程共享的部分是共享dirty内存。

(2) Total 的 PSS 信息

实际使用内存,这是另一种应用内存使用的计算方式,这个值就是我们应用真正占据的内存大小。 PSS会把跨进程的共享页也计算在内。任何独占的内存页直接计算它的PSS值,而和其它进程共享的页则按照共享的比例计算PSS值。例如,在两个进程间共享的页,计算进每个进程PPS的值是它的一半大小。 PSS计算方式的一个好处是:把所有进程的PSS值加起来就可以确定所有进程总共占用的内存。这意味着用PSS来计算进程的实际内存使用、进程间对比内存使用和总共剩余内存大小是很好的方式。

通常来说,只需关心Pss Total列和Private Dirty列就可以了。在一些情况下,Private Clean列和Heap Alloc列也会提供很有用的信息。

代码示例

/**
     * 获取进程内存Private Dirty数据
     *
     * @param context
     * @param pid
     *            进程ID
     * @return nativePrivateDirty、dalvikPrivateDirty、 TotalPrivateDirty
     */
    public static long[] getPrivDirty(Context context, int pid) {
        ActivityManager mAm = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        int[] pids = new int[1];
        pids[0] = pid;
        MemoryInfo[] memoryInfoArray = mAm.getProcessMemoryInfo(pids);
        MemoryInfo pidMemoryInfo = memoryInfoArray[0];
        long[] value = new long[3]; // Natvie Dalvik Total
        value[0] = pidMemoryInfo.nativePrivateDirty;
        value[1] = pidMemoryInfo.dalvikPrivateDirty;
        value[2] = pidMemoryInfo.getTotalPrivateDirty();
        return value;
    }
/**
    * 获取进程内存PSS数据
    *
    * @param context
    * @param pid
    * @return nativePss、dalvikPss、TotalPss
    */
   public static long[] getPSS(Context context, int pid) {
       long[] value = new long[3]; // Natvie Dalvik Total
       if (pid >= 0) {
           int[] pids = new int[1];
           pids[0] = pid;
           ActivityManager mAm = (ActivityManager) context
                   .getSystemService(Context.ACTIVITY_SERVICE);
           MemoryInfo[] memoryInfoArray = mAm.getProcessMemoryInfo(pids);
           MemoryInfo pidMemoryInfo = memoryInfoArray[0];
           value[0] = pidMemoryInfo.nativePss;
           value[1] = pidMemoryInfo.dalvikPss;
           value[2] = pidMemoryInfo.getTotalPss();
       } else {
           value[0] = 0;
           value[1] = 0;
           value[2] = 0;
       }
       return value;
   }

获取手机总内存和可用内存信息

“/proc/meminfo”文件记录了android手机的一些内存信息,通过读取文件”/proc/meminfo”的信息能够获取手机Memory的总量。

# cat /proc/meminfo
cat /proc/meminfo
MemTotal: 94096 kB           所有可用RAM大小。
MemFree: 1684 kB           LowFree与HighFree的总和,被系统留着未使用的内存。
Buffers: 16 kB           用来给文件做缓冲大小
Cached: 27160 kB   被高速缓冲存储器(cache memory)用的内存的大小(等于diskcache minus SwapCache)。
SwapCached: 0 kB           被高速缓冲存储器(cache memory)用的交换空间的大小。已经被交换出来的内存,仍然被存放在swapfile中,用来在需要的时候很快的被替换而不需要再次打开I/O端口。
Active: 35392 kB          在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非非常必要,否则不会被移作他用。
Inactive: 44180 kB           在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径。
Active(anon): 26540 kB          
Inactive(anon): 28244 kB          
Active(file): 8852 kB          
Inactive(file): 15936 kB          
Unevictable: 280 kB          
Mlocked: 0 kB          
SwapTotal: 0 kB           交换空间的总大小。
SwapFree: 0 kB           未被使用交换空间的大小。
Dirty: 0 kB          等待被写回到磁盘的内存大小。
Writeback: 0 kB          正在被写回到磁盘的内存大小。
AnonPages: 52688 kB          未映射页的内存大小。
Mapped: 17960 kB          设备和文件等映射的大小。
Slab: 3816 kB          内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗。
SReclaimable: 936 kB          可收回Slab的大小。
SUnreclaim: 2880 kB          不可收回Slab的大小(SUnreclaim+SReclaimable=Slab)。
PageTables: 5260 kB          管理内存分页页面的索引表的大小。
NFS_Unstable: 0 kB          不稳定页表的大小。
Bounce: 0 kB         
WritebackTmp: 0 kB         
CommitLimit: 47048 kB         
Committed_AS: 1483784 kB         
VmallocTotal: 876544 kB         
VmallocUsed: 15456 kB         
VmallocChunk: 829444 kB

要获取android手机总内存大小,只需读取”/proc/meminfo”文件的第1行,并进行简单的字符串处理即可。

代码示例

/**
     * 获取空闲内存和总内存拼接字符串
     *
     * @return 总内存
     */
    public static String getFreeAndTotalMem() {
        long[] memInfo = getMemInfo();
        return Long.toString(memInfo[1] + memInfo[2] + memInfo[3]) + "M/"
                + Long.toString(memInfo[0]) + "M";
    }
/**
     * 获取内存信息:total、free、buffers、cached,单位MB
     *
     * @return 内存信息
     */
    public static long[] getMemInfo() {
        long memInfo[] = new long[4];
        try {
            Class<?> procClazz = Class.forName("android.os.Process");
            Class<?> paramTypes[] = new Class[] { String.class, String[].class,
                    long[].class };
            Method readProclines = procClazz.getMethod("readProcLines",
                    paramTypes);
            Object args[] = new Object[3];
            final String[] memInfoFields = new String[] { "MemTotal:",
                    "MemFree:", "Buffers:", "Cached:" };
            long[] memInfoSizes = new long[memInfoFields.length];
            memInfoSizes[0] = 30;
            memInfoSizes[1] = -30;
            args[0] = new String("/proc/meminfo");
            args[1] = memInfoFields;
            args[2] = memInfoSizes;
            if (null != readProclines) {
                readProclines.invoke(null, args);
                for (int i = 0; i < memInfoSizes.length; i++) {
                    memInfo[i] = memInfoSizes[i] / 1024;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return memInfo;
    }

总结

1)Pss/SharedDirty/Private Dirty三列是读取了/proc/process-id/smaps文件获取的,可以通过adb shell cat /proc/process-id/smaps来查看(需要root)。这是个普通的linux文件,描述了进程的虚拟内存区域的具体信息。

2)Native HeapSize/Alloc/Free三列是使用C函数mallinfo得到的。

3)Dalvik HeapSize/Alloc/Free并非该cpp文件产生,而是android的Debug类生成。

meminfo结果详细分析

Pss对应的TOTAL值:内存所实际占用的值。

Dalvik Heap Size:从RuntimetotalMemory()获得,DalvikHeap总共的内存大小。

Dalvik HeapAlloc:RuntimetotalMemory()-freeMemory() ,Dalvik Heap分配的内存大小。

Dalvik Heap Free:从RuntimefreeMemory()获得,DalvikHeap剩余的内存大小。

Dalvik Heap Size 约等于Dalvik  HeapAlloc+ Dalvik  HeapFree。

Cursor:/dev/ashmem/Cursor Cursor消耗的内存(KB)。

Ashmem:/dev/ashmem,匿名共享内存用来提供共享内存通过分配一个多个进程可以共享的带名称的内存块。

Other dev:/dev/,内部driver占用的在 “Otherdev”。

.so mmap:C 库代码占用的内存。

.jar mmap:Java 文件代码占用的内存。

.apk mmap:apk代码占用的内存。

.ttf mmap:ttf 文件代码占用的内存。

.dex mmap:Dex 文件代码占用的内存。

Other mmap:其他文件占用的内存。
私有(Clean and Dirty)内存:

进程独占的内存。也就是应用进程销毁时系统可以直接回收的内存容量。通常来说,“private dirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储,因此不能做分页存储到外存(Android不支持swap)。所有分配的Dalvik堆和本地堆都是“private dirty”内存;Dalvik堆和本地堆中和Zygote进程共享的部分是共享dirty内存。

实际使用内存 (PSS):

这是另一种应用内存使用的计算方式,把跨进程的共享页也计算在内。任何独占的内存页直接计算它的PSS值,而和其它进程共享的页则按照共享的比例计算PSS值。例如,在两个进程间共享的页,计算进每个进程PPS的值是它的一半大小。PSS计算方式的一个好处是:把所有进程的PSS值加起来就可以确定所有进程总共占用的内存。这意味着用PSS来计算进程的实际内存使用、进程间对比内存使用和总共剩余内存大小是很好的方式。

通常来说,只需关心Pss Total列和Private Dirty列就可以了。在一些情况下,Private Clean列和Heap Alloc列也会提供很有用的信息。下面是一些应该查看的内存分配类型(行中列出的类型):

  • Dalvik Heap:

应用中Dalvik分配使用的内存。Pss Total包含所有的Zygote分配(如上面PSS定义所描述的,共享跨进程的加权)。Private Dirty是应用堆独占的内存大小,包含了独自分配的部分和应用进程从Zygote复制分裂时被修改的Zygote分配的内存页。注意:新平台版本有Dalvik Other这一项。Dalvik Heap中的Pss Total和Private Dirty不包括Dalvik的开销,例如即时编译(JIT)和垃圾回收(GC),然而老版本都包含在Dalvik的开销里面。

  • Heap Alloc:

是应用中Dalvik堆和本地堆已经分配使用的大小。它的值比Pss Total和Private Dirty大,因为进程是从Zygote中复制分裂出来的,包含了进程共享的分配部分。

  • .so mmap和.dex mmap:

mmap映射的.so(本地) 和.dex(Dalvik)代码使用的内存。Pss Total 包含了跨应用共享的平台代码;Private Clean是应用独享的代码。通常来说,实际映射的内存大小要大一点——这里显示的内存大小是执行了当前操作后应用使用的内存大小。然而,.so mmap 的private dirty比较大,这是由于在加载到最终地址时已经为本地代码分配好了内存空间。

  • Unknown:

无法归类到其它项的内存页。目前,这主要包含大部分的本地分配,就是那些在工具收集数据时由于地址空间布局随机化(Address Space Layout Randomization ,ASLR)不能被计算在内的部分。和Dalvik堆一样, Unknown中的Pss Total把和Zygote共享的部分计算在内,Unknown中的Private Dirty只计算应用独自使用的内存。

  • TOTAL:

进程总使用的实际使用内存(PSS),是上面所有PSS项的总和。它表明了进程总的内存使用量,可以直接用来和其它进程或总的可以内存进行比较。Private Dirty和Private Clean是进程独自占用的总内存,不会和其它进程共享。当进程销毁时,它们(特别是Private Dirty)占用的内存会重新释放回系统。Dirty内存是已经被修改的内存页,因此必须常驻内存(因为没有swap);Clean内存是已经映射持久文件使用的内存页(例如正在被执行的代码),因此一段时间不使用的话就可以置换出去。

  • ViewRootImpl:

进程中活动的根视图的数量。每个根视图与一个窗口关联,因此可以帮助确定涉及对话框和窗口的内存泄露。

  • AppContexts和Activities:

当前驻留在进程中的Context和Activity对象的数量。可以很快的确认常见的由于静态引用而不能被垃圾回收的泄露的 Activity对象。这些对象通常有很多其它相关联的分配,因此这是追查大的内存泄露的很好办法。

注意:View 和 Drawable 对象也持有所在Activity的引用,因此,持有View 或 Drawable 对象也可能会导致应用Activity泄露。

目录
相关文章
|
15天前
|
XML 存储 JSON
51. 【Android教程】JSON 数据解析
51. 【Android教程】JSON 数据解析
27 2
|
7天前
|
编解码 安全 Android开发
探索iOS与Android开发的差异:从界面到性能
【6月更文挑战第10天】在移动应用开发的广阔天地中,iOS和Android两大平台各占山头,它们在设计理念、用户体验、性能优化等方面展现出独特的魅力。本文将深入探讨这两大系统在开发过程中的主要差异,从用户界面设计到性能调优,揭示各自背后的技术逻辑与创新策略,为开发者提供全面的视角和实用的开发指南。
|
11天前
|
JSON 编解码 Apache
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
12 1
|
15天前
|
XML 存储 JavaScript
50. 【Android教程】xml 数据解析
50. 【Android教程】xml 数据解析
15 1
|
18天前
|
缓存 Android开发 开发者
安卓系统优化:提升手机性能的秘诀
【5月更文挑战第31天】本文将探讨如何通过一系列简单的步骤和技巧,对安卓系统进行优化,以提升手机的性能。我们将从清理无用文件、管理后台应用、调整系统设置等方面入手,帮助你的安卓设备运行更加流畅。
|
18天前
|
缓存 监控 Android开发
提升安卓应用性能的实用策略
【5月更文挑战第31天】 在移动设备愈发普及的今天,用户对安卓应用的性能要求也越来越高。一个流畅、响应迅速的应用能够显著提高用户体验和满意度。本文将深入探讨影响安卓应用性能的关键因素,并提出一系列实用的优化策略。从内存管理到代码效率,从UI渲染到网络通信,我们将逐一解析每个环节的性能瓶颈,并给出相应的解决方案。通过这些策略的实施,开发者可以显著提升应用的性能,为用户提供更加流畅和高效的使用体验。
19 0
|
19天前
|
缓存 监控 数据库
提升安卓应用性能的十大技巧
【5月更文挑战第30天】 在竞争激烈的应用市场中,一个流畅、高效的应用体验是吸引和保留用户的关键。对于安卓开发者来说,优化应用的性能是一个持续的挑战。本文将深入探讨十个实用的技巧来提升安卓应用的性能,包括内存管理、UI渲染、多线程处理等关键领域。这些技巧不仅有助于改善应用的响应速度和稳定性,还能确保在不同设备上的兼容性和效率。通过实践这些策略,开发者能够为用户提供更加流畅和愉悦的使用体验。
|
20天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【5月更文挑战第29天】 在移动开发领域,性能优化一直是开发者追求的关键目标。随着Kotlin在Android开发中的普及,了解其与传统Java语言在性能方面的差异成为一项重要议题。本文通过深入分析和对比两种语言的运行效率、启动时间以及内存消耗,为开发者在选择编程语言时提供数据支持和实践指南,从而帮助他们构建更加高效的Android应用。
|
20天前
|
缓存 Java 数据库
提升安卓应用性能的实用策略
【5月更文挑战第29天】 在竞争激烈的移动市场中,一个流畅且响应迅速的应用程序是获得用户青睐的关键。本文将探讨针对安卓平台的性能优化技巧,从内存管理到多线程处理,从布局优化到高效的资源利用,旨在帮助开发者构建更高效、更稳定的应用体验。通过分析常见的性能瓶颈并提供解决方案,我们的目标是使应用启动更快、响应更迅捷,同时减少电量消耗,确保最终用户拥有最佳的使用体验。
|
20天前
|
监控 测试技术 Android开发
提升安卓应用性能的实用策略
【5月更文挑战第29天】 在竞争激烈的应用市场中,性能优化是提升用户体验和保持应用竞争力的关键。本文将探讨针对安卓平台的性能优化技巧,包括内存管理、多线程处理、UI渲染效率以及电池寿命优化等方面。我们将深入分析每种策略的原理,并通过实例说明如何实现这些优化措施,帮助开发者构建更快速、更流畅的安卓应用。