经常有同学问怎么样监控Android的内存。这里和大家聊聊我对Android内存的理解和获取方法。
一般说来,Android本质是个Linux系统,在操作系统里面,Linux内存使用是个是一个比较复杂和难以理解的。现在我们有很多app可以管理系统的内存,并且提供你Android系统的状态更新的功能。
如果你只关注Android应用层的框架(framework),用ActivityManager.getMemoryInfo方法去获取手机里面内存信息,还可以帮忙我们查看后台进程产生更多的内存信息,还有那些应用需要虚拟机杀掉的服务进程。如果对存java程序,这没什么用,是因为java的堆栈会限制app的进程去避免把内存压力施加给操作系统。
如果我们关注底层的话,我们可以用内核原生态的api获取内存的使用(后面详细给出命令)
回到刚刚说的应用层获取的api方式,我们可以获取三种不同的内存 "Pss", "PrivateDirty", and "SharedDirty"。这三种内存各不相同。
- VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
- RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
- PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
- USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
在Android系统里面有大量的内存都是靠多个进程共享同一片内存。所以多少内存实际过程中被使用真的是没办法知道。不知道不代表我们没法获取系统现在的内存。还有,你如果把所有RAM(随机存储内存)映射到每个进程中,并且相加,你最终得到的内存比实际内存大许多。
回到刚刚获取的三种内存上来,PSS是物理内存,它是度量一个内核计算,考虑到内存共享基础过程,RAM的每一页的页面也使用其他进程的比例,有了这个,你可以在理论上相加所有物理进程去看整个RAM里面内存使用的总数,并且比较PSS之间的进程来获取他们相对的权值。
另外一个度量是PrivateDirty类似私有内存,基本上RAM里面的内存是不能分页到磁盘内存处理的数据,而且不能和其他进程共享。换句话说PrivateDirty里面的RAM将成为系统可用内存,仅仅是当系统把他划入缓存或者其他用途或者进程被杀死。
故名思议,SharedDirty就是共享内存,这个主要是提供各个进程共享数据等。不做详细讨论。
利用adb桥接命令,我们也可以达到很多运行时系统的内存大量的信息。常见的命令是大家都知道的系统快照 "adb shell dumpsys meminfo"。它可以分割出每个java进程的内存使用情况,包含各种各样其他信息,你也可以加上名字和进程ID(PID)来查看它,比如:
** MEMINFO in pid 890 [system] ** native dalvik other total size: 10940 7047 N/A 17987 allocated: 8943 5516 N/A 14459 free: 336 1531 N/A 1867 (Pss): 4585 9282 11916 25783 (shared dirty): 2184 3596 916 6696 (priv dirty): 4504 5956 7456 17916 Objects Views: 149 ViewRoots: 4 AppContexts: 13 Activities: 0 Assets: 4 AssetManagers: 4 Local Binders: 141 Proxy Binders: 158 Death Recipients: 49 OpenSSL Sockets: 0 SQL heap: 205 dbFiles: 0 numPagers: 0 inactivePageKB: 0 activePageKB: 0
这一段主要是在Size这一行,它表示是整个制定的堆栈空间地址空间总的内存大小,allocated这一行是实际堆的分配空间KB为单位,free是额外剩余的堆栈空间大小,后面的pss和priv dirty是前面扯到的每个堆栈的页面指定的分配空间。
如果你仅仅想产科所有进程使用的内存,你用"adb shell procrank"这个命令就好了,运行后如下显示:
PID Vss Rss Pss Uss cmdline 890 84456K 48668K 25850K 21284K system_server 1231 50748K 39088K 17587K 13792K com.android.launcher2 947 34488K 28528K 10834K 9308K com.android.wallpaper 987 26964K 26956K 8751K 7308K com.google.process.gapps 954 24300K 24296K 6249K 4824K com.android.phone 948 23020K 23016K 5864K 4748K com.android.inputmethod.latin 888 25728K 25724K 5774K 3668K zygote 977 24100K 24096K 5667K 4340K android.process.acore ... 59 336K 332K 99K 92K /system/bin/installd 60 396K 392K 93K 84K /system/bin/keystore 51 280K 276K 74K 68K /system/bin/servicemanager 54 256K 252K 69K 64K /system/bin/debuggerdVss和Rss是基本的数据,Pss是物理内存,Uss差不多就是private Dirty。一般说来,USS和Pss都大于我们看到的内存信息。这是为什么呢?与内存信息本身相比,procrank用了不同内核机制去收集它们数据信息,这样才与实际结果不同。这个procrank类似在一个粮仓采取一点米粒大小的粮食,这也许是它收集内存信息不太准确的原因。
最后有个命令adb shell cat /proc/meminfo"给出了系统总的内存使用的总量。在大量的数据里面,只有很少的数据和信息值得去讨论:
MemTotal: 395144 kB MemFree: 184936 kB Buffers: 880 kB Cached: 84104 kB SwapCached: 0 kB
memtotal是内核和用户空间可用内存的总量,通常比设备的实际物理内存要少一些,因为RAM需要有缓存。
MemFree是不被使用的内存。通常我们看到的比较高,通常在Android系统仅仅只有几MB,因此我们试图用可用的内存来保持进程是可以运行的。
Cached是内存用于缓存文件系统做这样的事情。典型的情况是系统需要20MB空间去避免寻道坏的区域页面,Android系统杀手是可以被调节到特殊系统,为了确保后台进程被杀死之前去缓存RAM消耗了太多,而导致像这样的分页。
原文链接:http://stackoverflow.com/questions/2298208/how-do-i-discover-memory-usage-of-my-application-in-android
|