检查内存常用的命令
dumpsys meminfo
内存指标概念
Item 全称 含义 等价
USS Unique Set Size 物理内存 进程独占的内存
PSS Proportional Set Size 物理内存 PSS= USS+ 按比例包含共享库
RSS Resident Set Size 物理内存 RSS= USS+ 包含共享库
VSS Virtual Set Size 虚拟内存 VSS= RSS+ 未分配实际物理内存
一般我们看PSS,这个item能比较实际地反应进程所占的内存。这个指令罗列了根据各种指标排序的各个进程的PSS
- Total PSS by process
根据不同进程占据的内存大小来排序
- Total PSS by OOM adjustment
根据OOM时候杀进程的优先级,在需要杀进程留出空间的时候,从列表底部到高位依次杀掉进程
进程OOM kill优先级说明
android/frameworks/base/services/core/java/com/android/server/am/ProcessList.java
// (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;
复制代码
- Total PSS by category
该标签下统计系统中所有进程每个类别占用内存的总和,具体每个的含义后面按app来解释。
- 最后是整体内存使用信息的总结
其中Total PSS by OOM adjustment 列表的Cached标签下的进程是随时可以回收内存的缓存进程,所以该部分内存在后面会统计到Free RAM字段中
在命令后面加上 -package “package name” 可以看到指定进程的内存占用情况
一般我们看Dalvik Heap这个指标,右上角的Heap Size表示的是这个进程占用的总堆大小,分析整体情况看底部的total项。
下面是详细的参数说明:
- Pss Total:是一个进程实际使用的内存,该统计方法包括比例分配共享库占用的内存,即如果有三个进程共享了一个共享库,则平摊分配该共享库占用的内存。Pss Total统计方法的一个需要注意的地方是如果使用共享库的一个进程被杀死,则共享库的内存占用按比例分配到其他共享该库的进程中,而不是将内存资源返回给系统,这种情况下PssTotal不能够准确代表内存返回给系统的情况。
- Private Dirty:进程私有的脏页内存大小,该统计方法只包括进程私有的被修改的内存。
- Private Clear:进程私有的干净页内存大小,该统计方法只包括进程私有的没有被修改的内存。
- Swapped Dirty:被交换的脏页内存大小,该内存与其他进程共享。其中private Dirty + private Clean = Uss,该值是一个进程的使用的私有内存大小,即这些内存唯一被该进程所有。该统计方法真正描述了运行一个进程需要的内存和杀死一个进程释放的内存情况,是怀疑内存泄露最好的统计方法。共享比例:sharing_proportion = (Pss Total – private_clean – private_dirty) /(shared_clean+shared_dirty) 能够被共享的内存:swappable_pss = (sharing_proportion * shared_clean) + private_clean
- Native Heap:本地堆使用的内存,包括C/C++在堆上分配的内存
- Dalvik Heap:dalvik虚拟机使用的内存
- Dalvik other:除Dalvik和Native之外分配的内存,包括C/C++分配的非堆内存
- Cursor:数据库游标文件占用的内存
- Ashmem:匿名共享内存
- Stack:Dalvik栈占用的内存
- Other dev:其他的dev占用的内存
- .so mmap:so库占用的内存
- .jar mmap:.jar文件占用的内存
- .apk mmap:.apk文件占用的内存
- .ttf mmap:.ttf文件占用的内存
- .dex mmap:.dex文件占用的内存
- image mmap:图像文件占用的内存
- code mmap:代码文件占用的内存
- Other mmap:其他文件占用的内存
- Graphics:GPU使用图像时使用的内存
- GL:GPU使用GL绘制时使用的内存
- Memtrack:GPU使用多媒体、照相机时使用的内存
- Unknown:不知道的内存消耗
- Heap Size:堆的总内存大小
- Heap Alloc:堆分配的内存大小
- Heap Free:堆待分配的内存大小
- Native Heap | Heap Size : 从mallinfo usmblks获的,当前进程Native堆的最大总共分配内存
- Native Heap | Heap Alloc : 从mallinfo uorblks获的,当前进程navtive堆的总共分配内存
- Native Heap | Heap Free : 从mallinfo fordblks获的,当前进程Native堆的剩余内存
- Native Heap Size ≈ Native Heap Alloc + Native Heap Free
- mallinfo是一个C库,mallinfo()函数提供了各种各样通过malloc()函数分配的内存的统计信息
- Dalvik Heap | Heap Size : 从Runtime totalMemory()获得,Dalvik Heap总共的内存大小
- Dalvik Heap | Heap Alloc : 从Runtime totalMemory() – freeMemory()获得,Dalvik Heap分配的内存大小
- Dalvik Heap | Heap Free : 从Runtime freeMemory()获得,Dalvik Heap剩余的内存大小Dalvik Heap Size = Dalvik Heap Alloc + Dalvik Heap Free
Obejcts 当前进程中的对象个数
- Views: 当前进程中实例化的视图View对象数量
- ViewRootImpl:当前进程中实例化的视图根ViewRootImpl对象数量,代表一个窗口
- AppContexts:当前进程中实例化的应用上下文ContextImpl对象数量
- Activities:当前进程中实例化的Activity对象数量
- Assets:当前进程的全局资产数量
- AssetManagers:当前进程的全局资产管理数量
- Local Binders:当前进程有效的本地binder对象数量
- Proxy Binders:当前进程中引用的远程binder对象数量
- Death Recipients:当前进程到binder的无效链接数量
- OpenSSL Sockets:安全套接字对象数量
SQL
- MEMORY_USED:当前进程中数据库使用的内存数量,kb
- PAGECACHE_OVERFLOW:页面缓存的配置不能够满足的数量,kb
- MALLOC_SIZE: 向sqlite3请求的最大内存分配数量,kb
DATABASES
- pgsz:数据库的页面大小
- dbsz:数据库大小
- Lookaside(b):后备使用的内存大小
- cache:数据缓存状态
- Dbname:数据库表名
- Asset Allocations 资源路径和资源大小
知道了这些参数的含义,那据此我们分析内存泄漏的惯常方法应该是什么呢?
很简单,可以反复执行某个被怀疑的用例,然后观察dumpsys meminfo 指令结果中展示的heap size大小,如果堆大小一直在增加,那很可能是有内存泄漏,或者指定包名,观察指令结果中activity数量,如果数量一直在增加,很可能activity内存泄漏了。
procrank
获取所有进程的内存使用的排行榜,排行是以 Pss 的大小而排序。 procrank 命令比 dumpsys meminfo 命令,能输出更详细的VSS/RSS/PSS/USS内存指标。
cat /proc/meminfo
能否查看更加详细的内存信息
free
查看可用内存,缺省单位KB。该命令比较简单、轻量,专注于查看剩余内存情况。
showmap
vmstat
总结
- dumpsys meminfo 适用场景: 查看进程的oom adj,或者dalvik/native等区域内存情况,或者某个进程或apk的内存情况,功能非常强大;
- procrank 适用场景: 查看进程的VSS/RSS/PSS/USS各个内存指标;
- cat /proc/meminfo 适用场景: 查看系统的详尽内存信息,包含内核情况;
- free 适用场景: 只查看系统的可用内存;
- showmap 适用场景: 查看进程的虚拟地址空间的内存分配情况;
- vmstat 适用场景: 周期性地打印出进程运行队列、系统切换、CPU时间占比等情况;