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泄露。

目录
相关文章
|
19天前
|
移动开发 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【4月更文挑战第3天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin的兴起,其在Android开发中的地位逐渐上升,但关于其与Java在性能方面的对比,尚无明确共识。本文通过深入分析并结合实际测试数据,探讨了Kotlin与Java在Android平台上的性能表现,揭示了在不同场景下两者的差异及其对应用性能的潜在影响,为开发者在选择编程语言时提供参考依据。
|
24天前
|
缓存 监控 Java
构建高效Android应用:从优化用户体验到提升性能
在竞争激烈的移动应用市场中,为用户提供流畅和高效的体验是至关重要的。本文深入探讨了如何通过多种技术手段来优化Android应用的性能,包括UI响应性、内存管理和多线程处理。同时,我们还将讨论如何利用最新的Android框架和工具来诊断和解决性能瓶颈。通过实例分析和最佳实践,读者将能够理解并实施必要的优化策略,以确保他们的应用在保持响应迅速的同时,还能够有效地利用系统资源。
|
1月前
|
缓存 移动开发 Android开发
提升安卓应用性能的实用策略
在移动开发领域,应用的性能优化是一个持续的挑战。对于安卓开发者而言,确保应用流畅、快速并且电池使用效率高,是吸引和保持用户的关键因素之一。本文将深入探讨针对安卓平台的性能优化技巧,包括内存管理、代码效率、UI渲染以及电池寿命等方面的考量。这些策略旨在帮助开发者构建出更高效、响应更快且用户体验更佳的安卓应用。
|
1月前
|
数据库 Android开发 UED
提升安卓应用性能的十大技巧
【2月更文挑战第30天】在移动设备上,应用程序的性能直接影响用户体验。本文将分享10个优化安卓应用性能的技巧,包括代码优化、内存管理、UI设计和使用性能分析工具等,帮助开发者提高应用的运行速度和响应时间,从而提升用户满意度。
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第30天】 随着Kotlin成为开发Android应用的首选语言,开发者社区对于其性能表现持续关注。本文通过深入分析与基准测试,探讨Kotlin与Java在Android平台上的性能差异,揭示两种语言在编译效率、运行时性能和内存消耗方面的具体表现,并提供优化建议。我们的目标是为Android开发者提供科学依据,帮助他们在项目实践中做出明智的编程语言选择。
|
1月前
|
监控 测试技术 Android开发
提升安卓应用性能的实用策略
【2月更文挑战第24天】 在竞争激烈的应用市场中,性能优化是提高用户体验和应用成功的关键。本文将探讨针对安卓平台的性能优化技巧,包括内存管理、多线程处理和UI渲染效率的提升。我们的目标是为开发者提供一套实用的工具和方法,以诊断和解决性能瓶颈,确保应用流畅运行。
|
1月前
|
安全 Java Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第24天】在移动开发领域,性能优化一直是开发者关注的焦点。随着Kotlin在Android开发中的普及,了解其与Java在性能方面的差异变得尤为重要。本文通过深入分析和对比两种语言的运行效率、启动时间、内存消耗等关键指标,揭示了Kotlin在实际项目中可能带来的性能影响,并提供了针对性的优化建议。
29 0
|
1月前
|
安全 Java Android开发
构建高效安卓应用:探究Kotlin与Java的性能对比
【2月更文挑战第22天】 在移动开发的世界中,性能优化一直是开发者们追求的关键目标。随着Kotlin在安卓开发中的普及,许多团队面临是否采用Kotlin替代Java的决策。本文将深入探讨Kotlin和Java在安卓平台上的性能差异,通过实证分析和基准测试,揭示两种语言在编译效率、运行时性能以及内存占用方面的表现。我们还将讨论Kotlin的一些高级特性如何为性能优化提供新的可能性。
63 0
|
27天前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
在开发高性能的Android应用时,选择合适的编程语言至关重要。近年来,Kotlin因其简洁性和功能性受到开发者的青睐,但其性能是否与传统的Java相比有所不足?本文通过对比分析Kotlin与Java在Android平台上的运行效率,揭示二者在编译速度、运行时性能及资源消耗方面的具体差异,并探讨在实际项目中如何做出最佳选择。
17 4
|
1月前
|
Java 编译器 Android开发
构建高效Android应用:探究Kotlin与Java的性能差异
【2月更文挑战第24天】 在移动开发领域,性能优化一直是开发者关注的重点。随着Kotlin的兴起,许多Android开发者开始从传统的Java转向Kotlin进行应用开发。本文将深入探讨Kotlin与Java在Android平台上的性能表现,通过对比分析两者在编译效率、运行时性能和内存消耗等方面的差异。我们将基于实际案例研究,为开发者提供选择合适开发语言的数据支持,并分享一些提升应用性能的最佳实践。