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

相关文章
|
3月前
|
移动开发 监控 前端开发
构建高效Android应用:从优化布局到提升性能
【7月更文挑战第60天】在移动开发领域,一个流畅且响应迅速的应用程序是用户留存的关键。针对Android平台,开发者面临的挑战包括多样化的设备兼容性和性能优化。本文将深入探讨如何通过改进布局设计、内存管理和多线程处理来构建高效的Android应用。我们将剖析布局优化的细节,并讨论最新的Android性能提升策略,以帮助开发者创建更快速、更流畅的用户体验。
63 10
|
3月前
|
开发工具 Android开发 开发者
Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?
本文介绍了一种在Android平台上实现实时截图快照的方法,尤其适用于无需依赖系统接口的情况,如在RTMP推送、RTSP服务或GB28181设备接入等场景下进行截图。通过底层模块(libSmartPublisher.so)实现了截图功能,封装了`SnapShotImpl.java`类来管理截图流程。此外,提供了关键代码片段展示初始化SDK实例、执行截图、以及在Activity销毁时释放资源的过程。此方案还考虑到了快照数据的灵活处理需求,符合GB/T28181-2022的技术规范。对于寻求更灵活快照机制的开发者来说,这是一个值得参考的设计思路。
|
4天前
|
算法 JavaScript Android开发
|
2月前
|
Android开发 开发者 索引
Android实战经验之如何使用DiffUtil提升RecyclerView的刷新性能
本文介绍如何使用 `DiffUtil` 实现 `RecyclerView` 数据集的高效更新,避免不必要的全局刷新,尤其适用于处理大量数据场景。通过定义 `DiffUtil.Callback`、计算差异并应用到适配器,可以显著提升性能。同时,文章还列举了常见错误及原因,帮助开发者避免陷阱。
141 9
|
26天前
|
存储 大数据 数据库
Android经典面试题之Intent传递数据大小为什么限制是1M?
在 Android 中,使用 Intent 传递数据时存在约 1MB 的大小限制,这是由于 Binder 机制的事务缓冲区限制、Intent 的设计初衷以及内存消耗和性能问题所致。推荐使用文件存储、SharedPreferences、数据库存储或 ContentProvider 等方式传递大数据。
41 0
|
2月前
|
安全 Android开发 数据安全/隐私保护
安卓与iOS的对决:移动操作系统的性能与创新
在当今智能手机市场,安卓和iOS两大操作系统一直处于竞争状态。本文将深入探讨它们在性能、安全性和用户体验方面的不同,并分析这些差异如何影响用户的选择。
54 3
|
2月前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
68 0
|
3月前
|
JSON Java Android开发
Android 开发者必备秘籍:轻松攻克 JSON 格式数据解析难题,让你的应用更出色!
【8月更文挑战第18天】在Android开发中,解析JSON数据至关重要。JSON以其简洁和易读成为首选的数据交换格式。开发者可通过多种途径解析JSON,如使用内置的`JSONObject`和`JSONArray`类直接操作数据,或借助Google提供的Gson库将JSON自动映射为Java对象。无论哪种方法,正确解析JSON都是实现高效应用的关键,能帮助开发者处理网络请求返回的数据,并将其展示给用户,从而提升应用的功能性和用户体验。
81 1
|
3月前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用