Android内存测试方法梳理和实现原理简析

5,693 阅读3分钟

废话不说,直接上干货。

1:代码的方式

代码中使用Debug的getMemoryInfo(Debug.MemoryInfo memoryInfo)或ActivityManager的MemoryInfo[] getProcessMemoryInfo(int[] pids)

ActivityManager mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo[] memoryInfoArray = mAm.getProcessMemoryInfo(pids);

MemoryInfo对象中可以看看详细的内存信息,字段如下: 目前很多内存测试工具都是采用这种方式,如哆啦A梦、GT等。这种方式简单方便

2:dumpsys 命令

adb shell dumpsys meminfo package_name|pid

一般关注关PSS列的这几个字段:

  • Native Heap:JNI层的内存
  • Dalvik Heap:Java层的内存分配情况
  • Total PSS :应用真正占据的内存大小

一般公司测试都是会采用这种方式获取内存数据的

3:smaps文件

Linux在2.6版本之后有一个proc伪文件,在它下面记录各种信息,其中在proc/pid/smaps记录某个pid的内,smaps记录内存详细的使用情况。使用下面的命令可以读文件的值

cat /proc/pid/smaps

文件格式如下:

文件字段意义:

  • 400ca000-400cb000:本段虚拟内存的地址范围
  • r-xp :文件权限,r(读)、w(写)、x(执行)、p表示私有,s代表共享,如果不具有哪项权限用"-"代替
  • 00000000 :映射文件的偏移量
  • b3:11 :文件设备号
  • 1345 :被映射到虚拟内存文件的映索节点
  • /system/lib/libplddbgutil.so:文件名称
  • Size:相应虚拟地址空间的大小
  • RSS: 正在使用的物理内存的大小
  • Shared_Clean: Rss中和其他进程共享的未使用页数
  • Shared_Dirty: Rss和其他进程共享已经使用的页数
  • Private_Clean: Rss私有区域未使用的页数
  • Private_Dirty: Rss私有区域已经使用的页数

smaps文件一般有啥作用呢,譬如我们通过dumpsys meminfo 获取内存时,发现某一项内存数据异常,想弄清楚数据都是有哪些文件产生,我们就可以通过读取smaps详细排查。

4:源码分析

我们执行dumpsys memInfo 命令后的代码执行流程是怎样的呢,dumpsys命令会根据传进来的参数通过函数checkService来找到具体的service, 然后执行该service的dump方法,最总达到dump service的目的。

那我们传进入的memInfo对应的是哪个service呢,这个我们需要查看ActivityManagerService.Java类,搜索一下memInfo,最后我们发现它对应的service是MemBinder。

image

我们点击MemBinder类看类内部的实现

image

方法内部首先会进行android.Manifest.permission.DUMP权限检查,最终调用 dumpApplicationMemoryUsage方法,我们再看dumpApplicationMemoryUsage方法做了哪些操作

image

这个方法内容比较多,这里我们只显示了它最终调的地方,我们最终发现最后会调用android.os.Debug.java类。

image

其实会调用android.os.Debug.java类调用了大量的Native方法实现的,android.os.Debug.java对应的native文件是android_os_Debug.cpp,上面的Debug.getMemoryInfo(pid, mi)实际上最后调用了 android_os_Debug.cpp的android_os_Debug_getDirtyPagesPid方法

image

android_os_Debug_getDirtyPagesPid方法调用了load_maps(int pid, stats_t* stats)方法

image

load_maps中是通过读取smaps文件内容,到此dumpsys memInfo的实现就非常清晰了。

第一种代码的实现方式,其实最后走的流程和上面的是一样的。

android_os_Debug.cpp地址: android_os_Debug.cpp文件

5:内存测试关注的点

1.内存是否持续上涨:进入某项功能内存增长,退出功能时内存是否下降

2.是否频繁的GC:频繁的gc可能是因为你的程序内存碎片导致的,这也是需要优化的一个方向

3.内存的峰值是否在单个应用允许的最大值之内