这次继续安卓专项测试之内存
Android系统中每个APP占内存会有私有和公共的两部分:ShareDirty、PrivateDirty。“PrivateDirty”内存是其最重要的部分,因为只被自己的进程使用。它只在内存中存储,因此不能做分页存储到外存(Android不支持swap)。所有分配的Dalvik堆和本地堆都是“private dirty”内存;Dalvik堆和本地堆中和Zygote进程共享的部分是共享dirty内存。
而Pss是另一种应用内存使用的计算方式,是把跨进程的共享页也计算在内 — 例如,在两个进程间共享的页,计算进每个进程PPS的值是它的一半大小。PSS计算方式的一个好处是:把所有进程的PSS值加起来就可以确定所有进程总共占用的内存。这意味着用PSS来计算进程的实际内存使用、进程间对比内存使用和总共剩余内存大小是很好的方式。
通常来说,我们只需关心Pss Total列和Private Dirty列就可以了
Android里最常用于观察进程内存的方法就是dumpsys meminfo
测试过程为打开app,然后进入游戏,玩一局,退出(重复三次),退出数据监控
SoloPi 测试结果(监控间隔为500ms)
(不知道为什么SoloPi的PSS内存,PrivateDirty内存数据 都为0)
PerfDog 图比较直观,很容易看出app内存存在异常,一直在增加,SoloPi全局占用也能看出内存不断增加,PerfDog增加幅度为80M,50M,53M,SoloPi全局占用内存增加幅度35M,48M,62M
用SoloPi测试app性能,有关内存方面,会生成全局占用,PSS内存,PrivateDirty内存三个文件
全局占用 = totalMemory - getAvailMemory;
RecordPattern pattern = new RecordPattern("全局占用", "MB", "Memory");
pattern.setStartTime(startTime);
pattern.setEndTime(endTime);
result.put(pattern, usedMemory);
usedMemory 在totalMemory - getAvailMemory(context)里面获取
usedMemory.add(new RecordPattern.RecordItem(System.currentTimeMillis(), (float)(totalMemory - getAvailMemory(context)), ""));
totalMemory ----> totalMemory = getTotalMemory()
/**
* 获取总内存数据
* @return
*/
private Long getTotalMemory() {
if (activityManager == null) {
return 0L;
}
MemoryInfo info = new MemoryInfo();
activityManager.getMemoryInfo(info);
return info.totalMem / BYTES_PER_MEGA;
}
public static Long getAvailMemory(Context cx) {// 获取android当前可用内存大小
if (cx == null) {
return 0L;
}
ActivityManager am = (ActivityManager) cx.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);
LogUtil.i(TAG, "Available memory: " + mi.availMem);
// mi.availMem; 当前系统的可用内存
return mi.availMem / BYTES_PER_MEGA;// 将获取的内存大小规格化
}
PSS内存,PrivateDirty内存计算如下:
// 对每个进程的数据都进行记录
ArrayList<RecordPattern.RecordItem>[] pidRecord = appMemory.get(pid);
pattern = new RecordPattern("PSS内存-" + pid, "MB", "Memory");
pattern.setStartTime(startTime);
pattern.setEndTime(endTime);
result.put(pattern, pidRecord[0]);
pattern = new RecordPattern("PrivateDirty内存-" + pid, "MB", "Memory");
pattern.setStartTime(startTime);
pattern.setEndTime(endTime);
result.put(pattern, pidRecord[1]);
PSS内存,PrivateDirty内存数据存储在pidRecord,该数据来源于 appMemory 赋值
appMemory.put(processNames[i], saveRecord);
appMemory --> saveRecord —> record
// 记录数据
saveRecord[0].add(record[0]);
saveRecord[1].add(record[1]);
// 当前记录
RecordPattern.RecordItem[] record = new RecordPattern.RecordItem[]{
new RecordPattern.RecordItem(System.currentTimeMillis(), pidMemoryInfo.getTotalPss() / 1024f, ""),
new RecordPattern.RecordItem(System.currentTimeMillis(), pidMemoryInfo.getTotalPrivateDirty() / 1024f, "")};
record[0] 为pss内存,record[1]PrivateDirty内存
/**
* Return total PSS memory usage in kB.
*/
public int getTotalPss() {
return dalvikPss + nativePss + otherPss + getTotalSwappedOutPss();
}
/**
* Return total private dirty memory usage in kB.
*/
public int getTotalPrivateDirty() {
return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
}
这两个为Debug.MemoryInfo方法