内存的定量分析是我们了解App性能、系统健康度,解决ANR、OOM,进行系统和App优化的重要指标。本文就盘点下当前有哪些统计Android内存使用量的方法。
前置知识
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
运行时内存分布
内存统计方法
一、adb命令
1.1 adb shell dumpsys meminfo packageName
dumpsys meminfo
1.2 adb shell top
top获取
二、Android studio profiler
Android studio->profiler->SESSIONS+选择特定应用
as profiler
三、代码中获取
3.1 通过Runtime获取
// App进程的虚拟机可使用最大内存,不包括Nativie
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / (1024*1024));
// App进程的虚拟机已经申请到的内存
int totalMemory= (int) (Runtime.getRuntime().totalMemory() / (1024*1024));
// App进程虚拟机已申请到但还未使用的内存
int freeMemory=(int)(Runtime.getRuntime().freeMemory() / (1024*1024));
// App java层已经使用的内存
int useMemoryOnJava = totalMemory - freeMemory;
Log.d("MemoryInfo", "this app's JVM can use Max java memory is " + maxMemory + "MB");
Log.d("MemoryInfo", "this app's JVM now get Total memory is " + totalMemory + "MB");
Log.d("MemoryInfo", "this app's JVM now freeMemory memory is " + freeMemory + "MB");
Log.d("MemoryInfo", "this app's JVM now use memory is " + useMemoryOnJava + "MB");
3.2 通过ActivityManager获取
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// 该设备整体内存情况
ActivityManager.MemoryInfo systemMemoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(systemMemoryInfo);
long sysTotalMemory = systemMemoryInfo.totalMem / (1024 * 1024);
long sysAvailableMemory = systemMemoryInfo.availMem / (1024 * 1024);
// 系统内存阈值,低于这个阈值,系统就要进行清理后台进程等操作
long sysThreshold = systemMemoryInfo.threshold / (1024 * 1024);
boolean sysNowIsLowMemory = systemMemoryInfo.lowMemory;
Log.d("MemoryInfo", "system Total Memory: " + sysTotalMemory + " MB");
Log.d("MemoryInfo", "system Available Memory: " +sysAvailableMemory + " MB");
Log.d("MemoryInfo","system Threshold: " + sysThreshold + " MB");
Log.d("MemoryInfo", "system now is Low Memory: " + sysNowIsLowMemory);
// 对每个App的java堆限制
int largeMemoryClass = activityManager.getLargeMemoryClass();
Log.d("MemoryInfo", "设置android:largeHeap=\"true\" , App Max memory is " + largeMemoryClass + "MB");
int memoryClass = activityManager.getMemoryClass();
Log.d("MemoryInfo", "App max memory is " + memoryClass + "MB");
// 获取本进程使用的内存情况值
int pid = android.os.Process.myPid();
int[] pids = new int[]{pid};
Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
Debug.MemoryInfo memoryInfo = memoryInfoArray[0];
// 获取总内存使用 它等于dalvikPss + nativePss + otherPss + TotalSwappedOutPss
int totalPss = memoryInfo.getTotalPss()/1024;
int totalPrivateDirty = memoryInfo.getTotalPrivateDirty()/1024;
int totalSharedDirty = memoryInfo.getTotalSharedDirty()/1024;
// 获取 Native 堆内存
int nativePss = memoryInfo.nativePss/1024;
int nativePrivateDirty = memoryInfo.nativePrivateDirty/1024;
int nativeSharedDirty = memoryInfo.nativeSharedDirty/1024;
// 获取 Dalvik 堆内存
int dalvikPss = memoryInfo.dalvikPss/1024;
int dalvikPrivateDirty = memoryInfo.dalvikPrivateDirty/1024;
int dalvikSharedDirty = memoryInfo.dalvikSharedDirty/1024;
Log.d("MemoryInfo", "Total PSS: " + totalPss + " MB");
Log.d("MemoryInfo", "Total Private Dirty: " + totalPrivateDirty + " MB");
Log.d("MemoryInfo", "Total Shared Dirty: " + totalSharedDirty + " MB");
Log.d("MemoryInfo", "Native PSS: " + nativePss + " MB");
Log.d("MemoryInfo", "Native Private Dirty: " + nativePrivateDirty + " MB");
Log.d("MemoryInfo", "Native Shared Dirty: " + nativeSharedDirty + " MB");
Log.d("MemoryInfo", "Dalvik PSS: " + dalvikPss + " MB");
Log.d("MemoryInfo", "Dalvik Private Dirty: " + dalvikPrivateDirty + " MB");
Log.d("MemoryInfo", "Dalvik Shared Dirty: " + dalvikSharedDirty + " MB");
疑问和思考
问题: 实际测试时候,用上述几种方法同时去获取内存占用情况,发现同一个指标大概率能发现有较大差距,为什么呢?
个人理解: 虚拟机启动时候必须是有一套内存管理方案的,各个方法也是通过不同的通信方式或者api从虚拟机内存管理方获取这些信息,不同的原因在于内存波动很快,不同统计方法获取原始数据后计算方法不同等原因;还有可能就是不同指标虽然暴露对上层意思相近,但是实际上代表不同的含义,这个还有待研究,了解这个的大佬可以评论区交流。
注意事项: 目前我们搞内存优化,等需要量化内存场景的时候需要确定好是使用哪种方法进行测试,并且需要通过多次获取求均值等方法进行。